(git:374b731)
Loading...
Searching...
No Matches
timings.F
Go to the documentation of this file.
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! **************************************************************************************************
17MODULE timings
18 USE base_hooks, ONLY: timeset_hook,&
20 USE callgraph, ONLY: callgraph_destroy,&
26 USE kinds, ONLY: default_string_length,&
27 dp,&
28 int_8
29 USE list, ONLY: &
31 list_size, list_timerenv_type
32 USE machine, ONLY: m_energy,&
33 m_flush,&
34 m_memory,&
36 USE offload_api, ONLY: offload_mem_info,&
48#include "../base/base_uses.f90"
49
50 IMPLICIT NONE
51 PRIVATE
52
54
55 ! these routines are currently only used by environment.F and f77_interface.F
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)
66
67 INTEGER, PUBLIC, PARAMETER :: default_timings_level = 1
69
70 CHARACTER(LEN=default_string_length), PUBLIC, PARAMETER :: root_cp2k_name = 'CP2K'
71
72CONTAINS
73
74! **************************************************************************************************
75!> \brief Registers handlers with base_hooks.F
76!> \author Ole Schuett
77! **************************************************************************************************
81 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 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 IF (PRESENT(timer_env)) timer_env_ => timer_env
98 IF (.NOT. PRESENT(timer_env)) CALL timer_env_create(timer_env_)
99 IF (.NOT. ASSOCIATED(timer_env_)) &
100 cpabort("add_timer_env: not associated")
101
102 CALL timer_env_retain(timer_env_)
103 IF (.NOT. list_isready(timers_stack)) CALL list_init(timers_stack)
104 CALL list_push(timers_stack, timer_env_)
105 END SUBROUTINE add_timer_env
106
107! **************************************************************************************************
108!> \brief creates a new timer env
109!> \param timer_env ...
110!> \author fawzi
111! **************************************************************************************************
112 SUBROUTINE timer_env_create(timer_env)
113 TYPE(timer_env_type), POINTER :: timer_env
114
115 ALLOCATE (timer_env)
116 timer_env%ref_count = 0
117 timer_env%trace_max = -1 ! tracing disabled by default
118 timer_env%trace_all = .false.
119 CALL routine_map_init(timer_env%routine_names)
120 CALL callgraph_init(timer_env%callgraph)
121 CALL list_init(timer_env%routine_stats)
122 CALL list_init(timer_env%callstack)
123 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 SUBROUTINE rm_timer_env()
134 TYPE(timer_env_type), POINTER :: timer_env
135
136 timer_env => list_pop(timers_stack)
137 CALL timer_env_release(timer_env)
138 IF (list_size(timers_stack) == 0) CALL list_destroy(timers_stack)
139 END SUBROUTINE rm_timer_env
140
141! **************************************************************************************************
142!> \brief returns the current timer env from the stack
143!> \return ...
144!> \author fawzi
145! **************************************************************************************************
146 FUNCTION get_timer_env() RESULT(timer_env)
147 TYPE(timer_env_type), POINTER :: timer_env
148
149 timer_env => list_peek(timers_stack)
150 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 SUBROUTINE timer_env_retain(timer_env)
158 TYPE(timer_env_type), POINTER :: timer_env
159
160 IF (.NOT. ASSOCIATED(timer_env)) &
161 cpabort("timer_env_retain: not associated")
162 IF (timer_env%ref_count < 0) &
163 cpabort("timer_env_retain: negativ ref_count")
164 timer_env%ref_count = timer_env%ref_count + 1
165 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 SUBROUTINE timer_env_release(timer_env)
173 TYPE(timer_env_type), POINTER :: timer_env
174
175 INTEGER :: i
176 TYPE(callgraph_item_type), DIMENSION(:), POINTER :: ct_items
177 TYPE(routine_stat_type), POINTER :: r_stat
178
179 IF (.NOT. ASSOCIATED(timer_env)) &
180 cpabort("timer_env_release: not associated")
181 IF (timer_env%ref_count < 0) &
182 cpabort("timer_env_release: negativ ref_count")
183 timer_env%ref_count = timer_env%ref_count - 1
184 IF (timer_env%ref_count > 0) RETURN
185
186 ! No more references left - let's tear down this timer_env...
187
188 DO i = 1, list_size(timer_env%routine_stats)
189 r_stat => list_get(timer_env%routine_stats, i)
190 DEALLOCATE (r_stat)
191 END DO
192
193 ct_items => callgraph_items(timer_env%callgraph)
194 DO i = 1, SIZE(ct_items)
195 DEALLOCATE (ct_items(i)%value)
196 END DO
197 DEALLOCATE (ct_items)
198
199 CALL routine_map_destroy(timer_env%routine_names)
200 CALL callgraph_destroy(timer_env%callgraph)
201 CALL list_destroy(timer_env%callstack)
202 CALL list_destroy(timer_env%routine_stats)
203 DEALLOCATE (timer_env)
204 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 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!$OMP MASTER
229
230 ! Default value, using a negative value when timing is not taken
231 cs_entry%walltime_start = -huge(1.0_dp)
232 cs_entry%energy_start = -huge(1.0_dp)
233 root_cp2k_id = routine_name2id(root_cp2k_name)
234 !
235 routine_name_dsl = routinen ! converte to default_string_length
236 routine_id = routine_name2id(routine_name_dsl)
237 !
238 ! Take timings when the timings_level is appropriated
239 IF (global_timings_level .NE. 0 .OR. routine_id .EQ. root_cp2k_id) THEN
240 cs_entry%walltime_start = m_walltime()
241 cs_entry%energy_start = m_energy()
242 END IF
243 timer_env => list_peek(timers_stack)
244
245 IF (len_trim(routinen) > default_string_length) THEN
246 cpabort('timings_timeset: routineN too long: "'//trim(routinen)//"'")
247 END IF
248
249 ! update routine r_stats
250 r_stat => list_get(timer_env%routine_stats, routine_id)
251 stack_size = list_size(timer_env%callstack)
252 r_stat%total_calls = r_stat%total_calls + 1
253 r_stat%active_calls = r_stat%active_calls + 1
254 r_stat%stackdepth_accu = r_stat%stackdepth_accu + stack_size + 1
255
256 ! add routine to callstack
257 cs_entry%routine_id = routine_id
258 CALL list_push(timer_env%callstack, cs_entry)
259
260 !..if debug mode echo the subroutine name
261 IF ((timer_env%trace_all .OR. r_stat%trace) .AND. &
262 (r_stat%total_calls < timer_env%trace_max)) THEN
263 WRITE (sformat, *) "(A,A,", max(1, 3*stack_size - 4), "X,I4,1X,I6,1X,A,A)"
264 WRITE (mystring, sformat) timer_env%trace_str, ">>", stack_size + 1, &
265 r_stat%total_calls, trim(r_stat%routineN), " start"
266 CALL offload_mem_info(gpumem_free, gpumem_total)
267 CALL m_memory(cpumem)
268 WRITE (line, '(A,A,I0,A,A,I0,A)') trim(mystring), &
269 " Hostmem: ", (cpumem + 1024*1024 - 1)/(1024*1024), " MB", &
270 " GPUmem: ", (gpumem_total - gpumem_free)/(1024*1024), " MB"
271 WRITE (timer_env%trace_unit, *) trim(line)
272 CALL m_flush(timer_env%trace_unit)
273 END IF
274
275 handle = routine_id
276
277 CALL offload_timeset(routinen)
278
279!$OMP END MASTER
280
281 END SUBROUTINE timeset_handler
282
283! **************************************************************************************************
284!> \brief End timer
285!> \param handle ...
286!> \par History
287!> none
288!> \author JGH
289! **************************************************************************************************
290 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 routine_id = handle
305
306!$OMP MASTER
307
308 CALL offload_timestop()
309
310 timer_env => list_peek(timers_stack)
311 cs_entry = list_pop(timer_env%callstack)
312 r_stat => list_get(timer_env%routine_stats, cs_entry%routine_id)
313
314 IF (handle /= cs_entry%routine_id) THEN
315 print *, "list_size(timer_env%callstack) ", list_size(timer_env%callstack), &
316 " handle ", handle, " list_size(timers_stack) ", list_size(timers_stack)
317 cpabort('mismatched timestop '//trim(r_stat%routineN)//' in routine timestop')
318 END IF
319
320 wt_elapsed = 0
321 en_elapsed = 0
322 ! Take timings only when the start time is >=0, i.e. the timings_level is appropriated
323 IF (cs_entry%walltime_start .GE. 0) THEN
324 wt_now = m_walltime()
325 en_now = m_energy()
326 ! add the elapsed time for this timeset/timestop to the time accumulator
327 wt_elapsed = wt_now - cs_entry%walltime_start
328 en_elapsed = en_now - cs_entry%energy_start
329 END IF
330 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 IF (r_stat%active_calls == 0) THEN
334 r_stat%incl_walltime_accu = r_stat%incl_walltime_accu + wt_elapsed
335 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 r_stat%excl_walltime_accu = r_stat%excl_walltime_accu + wt_elapsed
340 r_stat%excl_energy_accu = r_stat%excl_energy_accu + en_elapsed
341
342 stack_size = list_size(timer_env%callstack)
343 IF (stack_size > 0) THEN
344 prev_cs_entry = list_peek(timer_env%callstack)
345 prev_stat => list_get(timer_env%routine_stats, prev_cs_entry%routine_id)
346 ! we fixup the clock of the caller
347 prev_stat%excl_walltime_accu = prev_stat%excl_walltime_accu - wt_elapsed
348 prev_stat%excl_energy_accu = prev_stat%excl_energy_accu - en_elapsed
349
350 !update callgraph
351 routine_tuple = (/prev_cs_entry%routine_id, routine_id/)
352 c_stat => callgraph_get(timer_env%callgraph, routine_tuple, default_value=null(c_stat))
353 IF (.NOT. ASSOCIATED(c_stat)) THEN
354 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 CALL callgraph_set(timer_env%callgraph, routine_tuple, c_stat)
359 END IF
360 c_stat%total_calls = c_stat%total_calls + 1
361 c_stat%incl_walltime_accu = c_stat%incl_walltime_accu + wt_elapsed
362 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 IF ((timer_env%trace_all .OR. r_stat%trace) .AND. &
367 (r_stat%total_calls < timer_env%trace_max)) THEN
368 WRITE (sformat, *) "(A,A,", max(1, 3*stack_size - 4), "X,I4,1X,I6,1X,A,F12.3)"
369 WRITE (mystring, sformat) timer_env%trace_str, "<<", stack_size + 1, &
370 r_stat%total_calls, trim(r_stat%routineN), wt_elapsed
371 CALL offload_mem_info(gpumem_free, gpumem_total)
372 CALL m_memory(cpumem)
373 WRITE (line, '(A,A,I0,A,A,I0,A)') trim(mystring), &
374 " Hostmem: ", (cpumem + 1024*1024 - 1)/(1024*1024), " MB", &
375 " GPUmem: ", (gpumem_total - gpumem_free)/(1024*1024), " MB"
376 WRITE (timer_env%trace_unit, *) trim(line)
377 CALL m_flush(timer_env%trace_unit)
378 END IF
379
380!$OMP END MASTER
381
382 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 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 timer_env => list_peek(timers_stack)
408 timer_env%trace_max = trace_max
409 timer_env%trace_unit = unit_nr
410 timer_env%trace_str = trace_str
411 timer_env%trace_all = .true.
412 IF (.NOT. PRESENT(routine_names)) RETURN
413
414 ! setup routine-specific tracing
415 timer_env%trace_all = .false.
416 DO i = 1, SIZE(routine_names)
417 routine_id = routine_name2id(routine_names(i))
418 r_stat => list_get(timer_env%routine_stats, routine_id)
419 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 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 IF (.NOT. list_isready(timers_stack)) &
441 RETURN
442 IF (list_size(timers_stack) == 0) &
443 RETURN
444
445 timer_env => list_peek(timers_stack)
446 WRITE (unit_nr, '(/,A,/)') " ===== Routine Calling Stack ===== "
447 DO i = list_size(timer_env%callstack), 1, -1
448 cs_entry = list_get(timer_env%callstack, i)
449 r_stat => list_get(timer_env%routine_stats, cs_entry%routine_id)
450 WRITE (unit_nr, '(T10,I4,1X,A)') i, trim(r_stat%routineN)
451 END DO
452 CALL m_flush(unit_nr)
453
454 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 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 timer_env => list_peek(timers_stack)
472 routine_id = routine_map_get(timer_env%routine_names, routinen, default_value=-1)
473
474 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 IF (index(routinen(1:len_trim(routinen)), ' ') /= 0) THEN
479 cpabort("timings_name2id: routineN contains spaces: "//routinen)
480 END IF
481
482 ! register routine_name_dsl with new routine_id
483 routine_id = routine_map_size(timer_env%routine_names) + 1
484 CALL routine_map_set(timer_env%routine_names, routinen, routine_id)
485
486 ALLOCATE (r_stat)
487 r_stat%routine_id = routine_id
488 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 CALL list_push(timer_env%routine_stats, r_stat)
498 cpassert(list_size(timer_env%routine_stats) == routine_map_size(timer_env%routine_names))
499 END FUNCTION routine_name2id
500
501END MODULE timings
502
Central dispatch for basic hooks.
Definition base_hooks.F:12
procedure(timeset_interface), pointer, public timeset_hook
Definition base_hooks.F:61
procedure(timestop_interface), pointer, public timestop_hook
Definition base_hooks.F:62
subroutine, public callgraph_destroy(hash_map)
Deallocated the internal data-structures if the given hash map. Caution: If the stored keys or values...
Definition callgraph.F:120
subroutine, public callgraph_init(hash_map, initial_capacity)
Allocates the internal data-structures of the given hash map.
Definition callgraph.F:78
type(callgraph_item_type) function, dimension(:), pointer, public callgraph_items(hash_map)
Returns a pointer to an array of all key/value-items stored in the hash map. Caution: The caller is r...
Definition callgraph.F:383
type(call_stat_type) function, pointer, public callgraph_get(hash_map, key, default_value)
Gets a value for a given key from the hash map. If the key is not found the default_value will be ret...
Definition callgraph.F:255
subroutine, public callgraph_set(hash_map, key, value)
Stores, and possibly overwrites, a given value under a given key.
Definition callgraph.F:147
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public int_8
Definition kinds.F:54
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
An array-based list which grows on demand. When the internal array is full, a new array of twice the ...
Definition list.F:24
Machine interface based on Fortran 2003 and POSIX.
Definition machine.F:17
subroutine, public m_memory(mem)
Returns the total amount of memory [bytes] in use, if known, zero otherwise.
Definition machine.F:332
subroutine, public m_flush(lunit)
flushes units if the &GLOBAL flag is set accordingly
Definition machine.F:106
real(kind=dp) function, public m_energy()
returns the energy used since some time in the past. The precise meaning depends on the infrastructur...
Definition machine.F:219
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
Definition machine.F:123
Fortran API for the offload package, which is written in C.
Definition offload_api.F:12
subroutine, public offload_timestop()
Ends a timing range.
subroutine, public offload_timeset(routinen)
Starts a timing range.
subroutine, public offload_mem_info(free, total)
Gets free and total device memory.
integer(kind=int_4) function, public routine_map_get(hash_map, key, default_value)
Gets a value for a given key from the hash map. If the key is not found the default_value will be ret...
integer function, public routine_map_size(hash_map)
Returns the number of key/value-items currently stored in the hash map.
subroutine, public routine_map_init(hash_map, initial_capacity)
Allocates the internal data-structures of the given hash map.
Definition routine_map.F:77
subroutine, public routine_map_destroy(hash_map)
Deallocated the internal data-structures if the given hash map. Caution: If the stored keys or values...
subroutine, public routine_map_set(hash_map, key, value)
Stores, and possibly overwrites, a given value under a given key.
Types used by timings.F and timings_report.F The types in this module are used within dict or list,...
Types used by timings.F and timings_report.F Due to the fortran restriction on cicular module-depende...
Timing routines for accounting.
Definition timings.F:17
subroutine, public timings_register_hooks()
Registers handlers with base_hooks.F.
Definition timings.F:79
subroutine, public print_stack(unit_nr)
Print current routine stack.
Definition timings.F:432
type(timer_env_type) function, pointer, public get_timer_env()
returns the current timer env from the stack
Definition timings.F:147
subroutine, public timeset_handler(routinen, handle)
Start timer.
Definition timings.F:215
integer, save, public global_timings_level
Definition timings.F:68
subroutine, public timings_setup_tracing(trace_max, unit_nr, trace_str, routine_names)
Set routine tracer.
Definition timings.F:398
subroutine, public add_timer_env(timer_env)
adds the given timer_env to the top of the stack
Definition timings.F:93
subroutine, public rm_timer_env()
removes the current timer env from the stack
Definition timings.F:134
subroutine, public timer_env_release(timer_env)
releases the given timer env
Definition timings.F:173
subroutine, public timestop_handler(handle)
End timer.
Definition timings.F:291
subroutine, public timer_env_retain(timer_env)
retains the given timer env
Definition timings.F:158
integer, parameter, public default_timings_level
Definition timings.F:67
character(len=default_string_length), parameter, public root_cp2k_name
Definition timings.F:70