Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Timing routines for accounting
10 : !> \par History
11 : !> 02.2004 made a stacked version (of stacks...) [Joost VandeVondele]
12 : !> 11.2004 storable timer_envs (for f77 interface) [fawzi]
13 : !> 10.2005 binary search to speed up lookup in timeset [fawzi]
14 : !> 12.2012 Complete rewrite based on dictionaries. [ole]
15 : !> \author JGH
16 : ! **************************************************************************************************
17 : MODULE timings
18 : USE base_hooks, ONLY: timeset_hook,&
19 : timestop_hook
20 : USE callgraph, ONLY: callgraph_destroy,&
21 : callgraph_get,&
22 : callgraph_init,&
23 : callgraph_item_type,&
24 : callgraph_items,&
25 : callgraph_set
26 : USE kinds, ONLY: default_string_length,&
27 : dp,&
28 : int_8
29 : USE list, ONLY: &
30 : list_destroy, list_get, list_init, list_isready, list_peek, list_pop, list_push, &
31 : list_size, list_timerenv_type
32 : USE machine, ONLY: m_energy,&
33 : m_flush,&
34 : m_memory,&
35 : m_walltime
36 : USE offload_api, ONLY: offload_mem_info,&
37 : offload_timeset,&
38 : offload_timestop
39 : USE routine_map, ONLY: routine_map_destroy,&
40 : routine_map_get,&
41 : routine_map_init,&
42 : routine_map_set,&
43 : routine_map_size
44 : USE timings_base_type, ONLY: call_stat_type,&
45 : callstack_entry_type,&
46 : routine_stat_type
47 : USE timings_types, ONLY: timer_env_type
48 : #include "../base/base_uses.f90"
49 :
50 : IMPLICIT NONE
51 : PRIVATE
52 :
53 : PUBLIC :: print_stack, timings_register_hooks
54 :
55 : ! these routines are currently only used by environment.F and f77_interface.F
56 : PUBLIC :: add_timer_env, rm_timer_env, get_timer_env
57 : PUBLIC :: timer_env_retain, timer_env_release
58 : PUBLIC :: timings_setup_tracing
59 :
60 : ! global variables
61 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'timings'
62 : TYPE(list_timerenv_type), SAVE, PRIVATE :: timers_stack
63 :
64 : !API (via pointer assignment to hook, PR67982, not meant to be called directly)
65 : PUBLIC :: timeset_handler, timestop_handler
66 :
67 : INTEGER, PUBLIC, PARAMETER :: default_timings_level = 1
68 : INTEGER, PUBLIC, SAVE :: global_timings_level = default_timings_level
69 :
70 : CHARACTER(LEN=default_string_length), PUBLIC, PARAMETER :: root_cp2k_name = 'CP2K'
71 :
72 : CONTAINS
73 :
74 : ! **************************************************************************************************
75 : !> \brief Registers handlers with base_hooks.F
76 : !> \author Ole Schuett
77 : ! **************************************************************************************************
78 8530 : SUBROUTINE timings_register_hooks()
79 8530 : timeset_hook => timeset_handler
80 8530 : timestop_hook => timestop_handler
81 8530 : END SUBROUTINE timings_register_hooks
82 :
83 : ! **************************************************************************************************
84 : !> \brief adds the given timer_env to the top of the stack
85 : !> \param timer_env ...
86 : !> \par History
87 : !> 02.2004 created [Joost VandeVondele]
88 : !> \note
89 : !> for each init_timer_env there should be the symmetric call to
90 : !> rm_timer_env
91 : ! **************************************************************************************************
92 107841 : SUBROUTINE add_timer_env(timer_env)
93 : TYPE(timer_env_type), OPTIONAL, POINTER :: timer_env
94 :
95 : TYPE(timer_env_type), POINTER :: timer_env_
96 :
97 107841 : IF (PRESENT(timer_env)) timer_env_ => timer_env
98 17657 : IF (.NOT. PRESENT(timer_env)) CALL timer_env_create(timer_env_)
99 107841 : IF (.NOT. ASSOCIATED(timer_env_)) &
100 0 : CPABORT("add_timer_env: not associated")
101 :
102 107841 : CALL timer_env_retain(timer_env_)
103 107841 : IF (.NOT. list_isready(timers_stack)) CALL list_init(timers_stack)
104 107841 : CALL list_push(timers_stack, timer_env_)
105 107841 : END SUBROUTINE add_timer_env
106 :
107 : ! **************************************************************************************************
108 : !> \brief creates a new timer env
109 : !> \param timer_env ...
110 : !> \author fawzi
111 : ! **************************************************************************************************
112 17657 : SUBROUTINE timer_env_create(timer_env)
113 : TYPE(timer_env_type), POINTER :: timer_env
114 :
115 17657 : ALLOCATE (timer_env)
116 17657 : timer_env%ref_count = 0
117 : timer_env%trace_max = -1 ! tracing disabled by default
118 : timer_env%trace_all = .FALSE.
119 17657 : CALL routine_map_init(timer_env%routine_names)
120 17657 : CALL callgraph_init(timer_env%callgraph)
121 17657 : CALL list_init(timer_env%routine_stats)
122 17657 : CALL list_init(timer_env%callstack)
123 17657 : END SUBROUTINE timer_env_create
124 :
125 : ! **************************************************************************************************
126 : !> \brief removes the current timer env from the stack
127 : !> \par History
128 : !> 02.2004 created [Joost VandeVondele]
129 : !> \note
130 : !> for each rm_timer_env there should have been the symmetric call to
131 : !> add_timer_env
132 : ! **************************************************************************************************
133 107841 : SUBROUTINE rm_timer_env()
134 : TYPE(timer_env_type), POINTER :: timer_env
135 :
136 107841 : timer_env => list_pop(timers_stack)
137 107841 : CALL timer_env_release(timer_env)
138 107841 : IF (list_size(timers_stack) == 0) CALL list_destroy(timers_stack)
139 107841 : END SUBROUTINE rm_timer_env
140 :
141 : ! **************************************************************************************************
142 : !> \brief returns the current timer env from the stack
143 : !> \return ...
144 : !> \author fawzi
145 : ! **************************************************************************************************
146 107919 : FUNCTION get_timer_env() RESULT(timer_env)
147 : TYPE(timer_env_type), POINTER :: timer_env
148 :
149 107919 : timer_env => list_peek(timers_stack)
150 107919 : END FUNCTION get_timer_env
151 :
152 : ! **************************************************************************************************
153 : !> \brief retains the given timer env
154 : !> \param timer_env the timer env to retain
155 : !> \author fawzi
156 : ! **************************************************************************************************
157 116448 : SUBROUTINE timer_env_retain(timer_env)
158 : TYPE(timer_env_type), POINTER :: timer_env
159 :
160 116448 : IF (.NOT. ASSOCIATED(timer_env)) &
161 0 : CPABORT("timer_env_retain: not associated")
162 116448 : IF (timer_env%ref_count < 0) &
163 0 : CPABORT("timer_env_retain: negativ ref_count")
164 116448 : timer_env%ref_count = timer_env%ref_count + 1
165 116448 : END SUBROUTINE timer_env_retain
166 :
167 : ! **************************************************************************************************
168 : !> \brief releases the given timer env
169 : !> \param timer_env the timer env to release
170 : !> \author fawzi
171 : ! **************************************************************************************************
172 116448 : SUBROUTINE timer_env_release(timer_env)
173 : TYPE(timer_env_type), POINTER :: timer_env
174 :
175 : INTEGER :: i
176 116448 : TYPE(callgraph_item_type), DIMENSION(:), POINTER :: ct_items
177 : TYPE(routine_stat_type), POINTER :: r_stat
178 :
179 116448 : IF (.NOT. ASSOCIATED(timer_env)) &
180 0 : CPABORT("timer_env_release: not associated")
181 116448 : IF (timer_env%ref_count < 0) &
182 0 : CPABORT("timer_env_release: negativ ref_count")
183 116448 : timer_env%ref_count = timer_env%ref_count - 1
184 116448 : IF (timer_env%ref_count > 0) RETURN
185 :
186 : ! No more references left - let's tear down this timer_env...
187 :
188 3835114 : DO i = 1, list_size(timer_env%routine_stats)
189 3817457 : r_stat => list_get(timer_env%routine_stats, i)
190 3835114 : DEALLOCATE (r_stat)
191 : END DO
192 :
193 17657 : ct_items => callgraph_items(timer_env%callgraph)
194 6414717 : DO i = 1, SIZE(ct_items)
195 6414717 : DEALLOCATE (ct_items(i)%value)
196 : END DO
197 17657 : DEALLOCATE (ct_items)
198 :
199 17657 : CALL routine_map_destroy(timer_env%routine_names)
200 17657 : CALL callgraph_destroy(timer_env%callgraph)
201 17657 : CALL list_destroy(timer_env%callstack)
202 17657 : CALL list_destroy(timer_env%routine_stats)
203 17657 : DEALLOCATE (timer_env)
204 116448 : END SUBROUTINE timer_env_release
205 :
206 : ! **************************************************************************************************
207 : !> \brief Start timer
208 : !> \param routineN ...
209 : !> \param handle ...
210 : !> \par History
211 : !> none
212 : !> \author JGH
213 : ! **************************************************************************************************
214 1562563377 : SUBROUTINE timeset_handler(routineN, handle)
215 : CHARACTER(LEN=*), INTENT(IN) :: routineN
216 : INTEGER, INTENT(OUT) :: handle
217 :
218 : CHARACTER(LEN=400) :: line, mystring
219 : CHARACTER(LEN=60) :: sformat
220 : CHARACTER(LEN=default_string_length) :: routine_name_dsl
221 : INTEGER :: routine_id, stack_size
222 : INTEGER(KIND=int_8) :: cpumem, gpumem_free, gpumem_total
223 : INTEGER, SAVE :: root_cp2k_id
224 : TYPE(callstack_entry_type) :: cs_entry
225 : TYPE(routine_stat_type), POINTER :: r_stat
226 : TYPE(timer_env_type), POINTER :: timer_env
227 :
228 1562563377 : !$OMP MASTER
229 :
230 : ! Default value, using a negative value when timing is not taken
231 1562563377 : cs_entry%walltime_start = -HUGE(1.0_dp)
232 1562563377 : cs_entry%energy_start = -HUGE(1.0_dp)
233 1562563377 : root_cp2k_id = routine_name2id(root_cp2k_name)
234 : !
235 1562563377 : routine_name_dsl = routineN ! converte to default_string_length
236 1562563377 : routine_id = routine_name2id(routine_name_dsl)
237 : !
238 : ! Take timings when the timings_level is appropriated
239 1562563377 : IF (global_timings_level .NE. 0 .OR. routine_id .EQ. root_cp2k_id) THEN
240 1562563377 : cs_entry%walltime_start = m_walltime()
241 1562563377 : cs_entry%energy_start = m_energy()
242 : END IF
243 1562563377 : timer_env => list_peek(timers_stack)
244 :
245 1562563377 : IF (LEN_TRIM(routineN) > default_string_length) THEN
246 0 : CPABORT('timings_timeset: routineN too long: "'//TRIM(routineN)//"'")
247 : END IF
248 :
249 : ! update routine r_stats
250 1562563377 : r_stat => list_get(timer_env%routine_stats, routine_id)
251 1562563377 : stack_size = list_size(timer_env%callstack)
252 1562563377 : r_stat%total_calls = r_stat%total_calls + 1
253 1562563377 : r_stat%active_calls = r_stat%active_calls + 1
254 1562563377 : r_stat%stackdepth_accu = r_stat%stackdepth_accu + stack_size + 1
255 :
256 : ! add routine to callstack
257 1562563377 : cs_entry%routine_id = routine_id
258 1562563377 : CALL list_push(timer_env%callstack, cs_entry)
259 :
260 : !..if debug mode echo the subroutine name
261 1562563377 : IF ((timer_env%trace_all .OR. r_stat%trace) .AND. &
262 : (r_stat%total_calls < timer_env%trace_max)) THEN
263 0 : WRITE (sformat, *) "(A,A,", MAX(1, 3*stack_size - 4), "X,I4,1X,I6,1X,A,A)"
264 0 : WRITE (mystring, sformat) timer_env%trace_str, ">>", stack_size + 1, &
265 0 : r_stat%total_calls, TRIM(r_stat%routineN), " start"
266 0 : CALL offload_mem_info(gpumem_free, gpumem_total)
267 0 : CALL m_memory(cpumem)
268 0 : WRITE (line, '(A,A,I0,A,A,I0,A)') TRIM(mystring), &
269 0 : " Hostmem: ", (cpumem + 1024*1024 - 1)/(1024*1024), " MB", &
270 0 : " GPUmem: ", (gpumem_total - gpumem_free)/(1024*1024), " MB"
271 0 : WRITE (timer_env%trace_unit, *) TRIM(line)
272 0 : CALL m_flush(timer_env%trace_unit)
273 : END IF
274 :
275 1562563377 : handle = routine_id
276 :
277 1562563377 : CALL offload_timeset(routineN)
278 :
279 : !$OMP END MASTER
280 :
281 1562563377 : END SUBROUTINE timeset_handler
282 :
283 : ! **************************************************************************************************
284 : !> \brief End timer
285 : !> \param handle ...
286 : !> \par History
287 : !> none
288 : !> \author JGH
289 : ! **************************************************************************************************
290 1562563377 : SUBROUTINE timestop_handler(handle)
291 : INTEGER, INTENT(in) :: handle
292 :
293 : CHARACTER(LEN=400) :: line, mystring
294 : CHARACTER(LEN=60) :: sformat
295 : INTEGER :: routine_id, stack_size
296 : INTEGER(KIND=int_8) :: cpumem, gpumem_free, gpumem_total
297 : INTEGER, DIMENSION(2) :: routine_tuple
298 : REAL(KIND=dp) :: en_elapsed, en_now, wt_elapsed, wt_now
299 : TYPE(call_stat_type), POINTER :: c_stat
300 : TYPE(callstack_entry_type) :: cs_entry, prev_cs_entry
301 : TYPE(routine_stat_type), POINTER :: prev_stat, r_stat
302 : TYPE(timer_env_type), POINTER :: timer_env
303 :
304 1562563377 : routine_id = handle
305 :
306 1562563377 : !$OMP MASTER
307 :
308 1562563377 : CALL offload_timestop()
309 :
310 1562563377 : timer_env => list_peek(timers_stack)
311 1562563377 : cs_entry = list_pop(timer_env%callstack)
312 1562563377 : r_stat => list_get(timer_env%routine_stats, cs_entry%routine_id)
313 :
314 1562563377 : IF (handle /= cs_entry%routine_id) THEN
315 0 : PRINT *, "list_size(timer_env%callstack) ", list_size(timer_env%callstack), &
316 0 : " handle ", handle, " list_size(timers_stack) ", list_size(timers_stack)
317 0 : CPABORT('mismatched timestop '//TRIM(r_stat%routineN)//' in routine timestop')
318 : END IF
319 :
320 1562563377 : wt_elapsed = 0
321 1562563377 : en_elapsed = 0
322 : ! Take timings only when the start time is >=0, i.e. the timings_level is appropriated
323 1562563377 : IF (cs_entry%walltime_start .GE. 0) THEN
324 1562563377 : wt_now = m_walltime()
325 1562563377 : en_now = m_energy()
326 : ! add the elapsed time for this timeset/timestop to the time accumulator
327 1562563377 : wt_elapsed = wt_now - cs_entry%walltime_start
328 1562563377 : en_elapsed = en_now - cs_entry%energy_start
329 : END IF
330 1562563377 : r_stat%active_calls = r_stat%active_calls - 1
331 :
332 : ! if we're the last instance in the stack, we do the accounting of the total time
333 1562563377 : IF (r_stat%active_calls == 0) THEN
334 1559495735 : r_stat%incl_walltime_accu = r_stat%incl_walltime_accu + wt_elapsed
335 1559495735 : r_stat%incl_energy_accu = r_stat%incl_energy_accu + en_elapsed
336 : END IF
337 :
338 : ! exclusive time we always sum, since children will correct this time with their total time
339 1562563377 : r_stat%excl_walltime_accu = r_stat%excl_walltime_accu + wt_elapsed
340 1562563377 : r_stat%excl_energy_accu = r_stat%excl_energy_accu + en_elapsed
341 :
342 1562563377 : stack_size = list_size(timer_env%callstack)
343 1562563377 : IF (stack_size > 0) THEN
344 1529426957 : prev_cs_entry = list_peek(timer_env%callstack)
345 1529426957 : prev_stat => list_get(timer_env%routine_stats, prev_cs_entry%routine_id)
346 : ! we fixup the clock of the caller
347 1529426957 : prev_stat%excl_walltime_accu = prev_stat%excl_walltime_accu - wt_elapsed
348 1529426957 : prev_stat%excl_energy_accu = prev_stat%excl_energy_accu - en_elapsed
349 :
350 : !update callgraph
351 4588280871 : routine_tuple = (/prev_cs_entry%routine_id, routine_id/)
352 1529426957 : c_stat => callgraph_get(timer_env%callgraph, routine_tuple, default_value=Null(c_stat))
353 1529426957 : IF (.NOT. ASSOCIATED(c_stat)) THEN
354 6397060 : ALLOCATE (c_stat)
355 : c_stat%total_calls = 0
356 : c_stat%incl_walltime_accu = 0.0_dp
357 : c_stat%incl_energy_accu = 0.0_dp
358 6397060 : CALL callgraph_set(timer_env%callgraph, routine_tuple, c_stat)
359 : END IF
360 1529426957 : c_stat%total_calls = c_stat%total_calls + 1
361 1529426957 : c_stat%incl_walltime_accu = c_stat%incl_walltime_accu + wt_elapsed
362 1529426957 : c_stat%incl_energy_accu = c_stat%incl_energy_accu + en_elapsed
363 : END IF
364 :
365 : !..if debug mode echo the subroutine name
366 1562563377 : IF ((timer_env%trace_all .OR. r_stat%trace) .AND. &
367 : (r_stat%total_calls < timer_env%trace_max)) THEN
368 0 : WRITE (sformat, *) "(A,A,", MAX(1, 3*stack_size - 4), "X,I4,1X,I6,1X,A,F12.3)"
369 0 : WRITE (mystring, sformat) timer_env%trace_str, "<<", stack_size + 1, &
370 0 : r_stat%total_calls, TRIM(r_stat%routineN), wt_elapsed
371 0 : CALL offload_mem_info(gpumem_free, gpumem_total)
372 0 : CALL m_memory(cpumem)
373 0 : WRITE (line, '(A,A,I0,A,A,I0,A)') TRIM(mystring), &
374 0 : " Hostmem: ", (cpumem + 1024*1024 - 1)/(1024*1024), " MB", &
375 0 : " GPUmem: ", (gpumem_total - gpumem_free)/(1024*1024), " MB"
376 0 : WRITE (timer_env%trace_unit, *) TRIM(line)
377 0 : CALL m_flush(timer_env%trace_unit)
378 : END IF
379 :
380 : !$OMP END MASTER
381 :
382 1562563377 : END SUBROUTINE timestop_handler
383 :
384 : ! **************************************************************************************************
385 : !> \brief Set routine tracer
386 : !> \param trace_max maximum number of calls reported per routine.
387 : !> Setting this to zero disables tracing.
388 : !> \param unit_nr output unit used for printing the trace-messages
389 : !> \param trace_str short info-string which is printed along with every message
390 : !> \param routine_names List of routine-names.
391 : !> If provided only these routines will be traced.
392 : !> If not present all routines will traced.
393 : !> \par History
394 : !> 12.2012 added ability to trace only certain routines [ole]
395 : !> \author JGH
396 : ! **************************************************************************************************
397 0 : SUBROUTINE timings_setup_tracing(trace_max, unit_nr, trace_str, routine_names)
398 : INTEGER, INTENT(IN) :: trace_max, unit_nr
399 : CHARACTER(len=13), INTENT(IN) :: trace_str
400 : CHARACTER(len=default_string_length), &
401 : DIMENSION(:), INTENT(IN), OPTIONAL :: routine_names
402 :
403 : INTEGER :: i, routine_id
404 : TYPE(routine_stat_type), POINTER :: r_stat
405 : TYPE(timer_env_type), POINTER :: timer_env
406 :
407 0 : timer_env => list_peek(timers_stack)
408 0 : timer_env%trace_max = trace_max
409 0 : timer_env%trace_unit = unit_nr
410 0 : timer_env%trace_str = trace_str
411 0 : timer_env%trace_all = .TRUE.
412 0 : IF (.NOT. PRESENT(routine_names)) RETURN
413 :
414 : ! setup routine-specific tracing
415 0 : timer_env%trace_all = .FALSE.
416 0 : DO i = 1, SIZE(routine_names)
417 0 : routine_id = routine_name2id(routine_names(i))
418 0 : r_stat => list_get(timer_env%routine_stats, routine_id)
419 0 : r_stat%trace = .TRUE.
420 : END DO
421 :
422 : END SUBROUTINE timings_setup_tracing
423 :
424 : ! **************************************************************************************************
425 : !> \brief Print current routine stack
426 : !> \param unit_nr ...
427 : !> \par History
428 : !> none
429 : !> \author JGH
430 : ! **************************************************************************************************
431 246 : SUBROUTINE print_stack(unit_nr)
432 : INTEGER, INTENT(IN) :: unit_nr
433 :
434 : INTEGER :: i
435 : TYPE(callstack_entry_type) :: cs_entry
436 : TYPE(routine_stat_type), POINTER :: r_stat
437 : TYPE(timer_env_type), POINTER :: timer_env
438 :
439 : ! catch edge cases where timer_env is not yet/anymore available
440 246 : IF (.NOT. list_isready(timers_stack)) &
441 0 : RETURN
442 246 : IF (list_size(timers_stack) == 0) &
443 : RETURN
444 :
445 246 : timer_env => list_peek(timers_stack)
446 246 : WRITE (unit_nr, '(/,A,/)') " ===== Routine Calling Stack ===== "
447 1431 : DO i = list_size(timer_env%callstack), 1, -1
448 1185 : cs_entry = list_get(timer_env%callstack, i)
449 1185 : r_stat => list_get(timer_env%routine_stats, cs_entry%routine_id)
450 1431 : WRITE (unit_nr, '(T10,I4,1X,A)') i, TRIM(r_stat%routineN)
451 : END DO
452 246 : CALL m_flush(unit_nr)
453 :
454 246 : END SUBROUTINE print_stack
455 :
456 : ! **************************************************************************************************
457 : !> \brief Internal routine used by timestet and timings_setup_tracing.
458 : !> If no routine with given name is found in timer_env%routine_names
459 : !> then a new entiry is created.
460 : !> \param routineN ...
461 : !> \return ...
462 : !> \author Ole Schuett
463 : ! **************************************************************************************************
464 3125126754 : FUNCTION routine_name2id(routineN) RESULT(routine_id)
465 : CHARACTER(LEN=default_string_length), INTENT(IN) :: routineN
466 : INTEGER :: routine_id
467 :
468 : TYPE(routine_stat_type), POINTER :: r_stat
469 : TYPE(timer_env_type), POINTER :: timer_env
470 :
471 3125126754 : timer_env => list_peek(timers_stack)
472 3125126754 : routine_id = routine_map_get(timer_env%routine_names, routineN, default_value=-1)
473 :
474 3125126754 : IF (routine_id /= -1) RETURN ! found an id - let's return it
475 : ! routine not found - let's create it
476 :
477 : ! enforce space free timer names, to make the output of trace/timings of a fixed number fields
478 3817457 : IF (INDEX(routineN(1:LEN_TRIM(routineN)), ' ') /= 0) THEN
479 0 : CPABORT("timings_name2id: routineN contains spaces: "//routineN)
480 : END IF
481 :
482 : ! register routine_name_dsl with new routine_id
483 3817457 : routine_id = routine_map_size(timer_env%routine_names) + 1
484 3817457 : CALL routine_map_set(timer_env%routine_names, routineN, routine_id)
485 :
486 3817457 : ALLOCATE (r_stat)
487 3817457 : r_stat%routine_id = routine_id
488 3817457 : r_stat%routineN = routineN
489 : r_stat%active_calls = 0
490 : r_stat%excl_walltime_accu = 0.0_dp
491 : r_stat%incl_walltime_accu = 0.0_dp
492 : r_stat%excl_energy_accu = 0.0_dp
493 : r_stat%incl_energy_accu = 0.0_dp
494 : r_stat%total_calls = 0
495 : r_stat%stackdepth_accu = 0
496 : r_stat%trace = .FALSE.
497 3817457 : CALL list_push(timer_env%routine_stats, r_stat)
498 3817457 : CPASSERT(list_size(timer_env%routine_stats) == routine_map_size(timer_env%routine_names))
499 : END FUNCTION routine_name2id
500 :
501 : END MODULE timings
502 :
|