Timers¶
Timers enable one to get the computation time of a specific task. For example, one would want to know the computation time to extract data in files. To get this information one can create a timer. In the following paragraphs, we will present the extent of the timers
structure that contains a set of timers (of type single_timer
).
Timers' structure¶
First, we will present the parametrization of a single timer single_timer
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
A timer focuses on the synthetization of one task's computation time. A timer (from the structure single_timer
) defines the time spent on a task by :
nb_calls
: number of times the task is executed, or more specificly the number of times the timer is started and stopped.total
: the total time spent on the task (cumulative time)mean
: the average time spent on the taskvariance
: the variance of the time spent on the taskmin
: the minimum time spent on the taskmax
: the maximum time spent on the tasks
: saves the system's time when the timer is startede
: saves the system's time when the timer is stoppedstarted
: logical parameter to define if the timer has been started or not
Usually, one would want to check the time spent on several tasks. Therefore, a timers
structure has been created to manage all the timers linked to all the reviewed tasks.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
This structure timers
contains a table of timers to analyse each task. This structure contains the number of timers nb_total
, the index nb_nolabel
of the timer if the timer has no label, the index active
of the active timer, and the index of the master timer master
. The variable stopped
only checks if all the timers are stopped. The rate
determines the number of the processor's clock ticks per second.
To use a timer to track a task, one first to initialize it by calling the timers_init
subroutine.
1 2 3 4 5 6 7 8 |
|
One initialize a timer by eventually specifying its label and if it is a master timer. If one wishes to get the timer's index in the timers table, one has to give the output variable timerid
stocking this index.
Set timer master
If one wants to set a timer as the timer master, one can call the timers_set_master
subroutine separately from the initialization.
1 2 3 4 5 6 |
|
When the timer is initialized, one can start the timer by calling timers_start
and specifying its index in the timers table or its label.
1 2 3 4 5 6 7 |
|
When the studied task is over, one can stop the timer and know the time spent on this task by calling timers_stop
and specifying the timer's index or label.
1 2 3 4 5 6 7 |
|
?? NOT SURE
One can also get the time spent on successive small tasks by calling timers_tic
at the beginning of each small task. If one wishes to have a timer report for each small task, one should specify withprint = .true.
. The timer is stopped by calling timers_toc
or by starting a new timer (the new timer will be the active
one).
??
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Reset
One can also reset the information concerning a timer by calling timers_reset
and specifying the timer's label or index. The timers_allreset
subroutine resets all timers.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The timers_allstart
and timers_allstop
routines just switch stopped
to .false.
or .true.
.
1 2 3 4 5 6 7 8 9 10 11 |
|
Usage¶
The following paragraph will provide an example of the timers
structure use. First, one needs to initialize the required timers. For example, one wishes to know the total simulation time, the time spent on MPI communications, the time spent on the computation of one time step, the time spent on boundary conditions' computation, etc.
type(timers) :: timer
integer :: timer_id(100)
[...]
call timer%init( label='Time of simulation' , timerid=timer_id(1) )
call timer%init( label='MPI_SEND_RECV' , timerid=timer_id(2) )
call timer%init( label='Time Step Computation' , timerid=timer_id(3) )
call timer%init( label='Boundary Conditions' , timerid=timer_id(4) )
[...]
To get the time spent on a task, one has to start a timer at the beginning of each task's execution. Here for example, the timer 'Time of simulation' will be started at the beginning of the program and stopped at the end of the program, but the timer 'MPI_SEND_RECV' will be started at the beginning of each MPI communication and stopped at the end of each communication.
type(timers) :: timer
integer :: timer_id(100)
[...]
call timer%start( label='MPI_SEND_RECV' ) ! Timer identified by its label
[...] ! MPI communication
call timer%stop( timerid=timer_id(2) ) ! Timer identified by its id
For example, still concerning MPI communications, one can also track the time spent on successive MPI communications :
type(timers) :: mpi_timer
call mpi_timer%tic( 'First MPI communication', withprint=.true. )
[...] ! First MPI communication
call mpi_timer%tic( 'Second MPI communication', withprint=.true. )
[...] ! Second MPI communication
[...]
call mpi_timer%tic( 'Last MPI communication', withprint=.true. )
[...] ! Last MPI communication
call mpi_timer%toc
call mpi_timer%report
Tic ...
One does not need to initialize each timer when using the tic
subroutine.
The report
subroutine prints a report of the timers' informations concerning the time spent on various tasks.