-
Notifications
You must be signed in to change notification settings - Fork 1
/
timers.F90
248 lines (227 loc) · 8.59 KB
/
timers.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
!Timing services (threadsafe).
!AUTHOR: Dmitry I. Lyakh (Liakh): [email protected]
!REVISION: 2018/07/24
!Copyright (C) 2014-2016 Dmitry I. Lyakh (Liakh)
!Copyright (C) 2014-2016 Oak Ridge National Laboratory (UT-Battelle)
!This file is part of ExaTensor.
!ExaTensor is free software: you can redistribute it and/or modify
!it under the terms of the GNU Lesser General Public License as published
!by the Free Software Foundation, either version 3 of the License, or
!(at your option) any later version.
!ExaTensor is distributed in the hope that it will be useful,
!but WITHOUT ANY WARRANTY; without even the implied warranty of
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
!GNU Lesser General Public License for more details.
!You should have received a copy of the GNU Lesser General Public License
!along with ExaTensor. If not, see <http://www.gnu.org/licenses/>.
!NOTES:
! # A timer handle (reference to an internal timer object) is thread-private:
! Only the thread which acquired the timer is allowed to deal with it later.
!PREPROCESSOR:
! # -D NO_OMP: Disable OpenMP (switch to Fortran cpu_time);
! # -D USE_GNU: Switch to the GNU Fortran timing (secnds);
! # -D NO_PHI: Ignore Intel MIC;
module timers
#ifndef NO_OMP
use omp_lib
#endif
implicit none
private
!PARAMETERS:
integer, parameter, private:: MAX_TIMERS=8192
integer, parameter, public:: TIMERS_SUCCESS=0
integer, parameter, public:: TIMERS_ERR_INVALID_ARG=1
integer, parameter, public:: TIMERS_ERR_NO_TIMERS_LEFT=2
integer, parameter, public:: TIMERS_ERR_TIMER_NULL=3
!TYPES:
type, private:: timer_t
real(8), private:: beg_time !time the timer started (sec)
real(8), private:: time_interval !time the timer is set for (sec)
end type timer_t
!GLOBAL DATA:
integer, private:: j_
type(timer_t), private:: timer(0:MAX_TIMERS-1)=(/(timer_t(-1d0,-1d0),j_=0,MAX_TIMERS-1)/)
integer, private:: handle_stack(0:MAX_TIMERS-1)=(/(j_,j_=0,MAX_TIMERS-1)/)
integer, private:: handle_sp=0
real(8), private:: timer_tick=-1d0 !uninitilized
!FUNCTION VISIBILITY:
public timer_start
public timer_expired
public timer_reset
public timer_destroy
public timer_tick_sec
public thread_wtime
public accu_time
public time_sys_sec
public time_high_sec
!EXTERNAL INTERFACES:
interface
function accu_time() bind(C,name='accu_time')
use, intrinsic:: ISO_C_BINDING, only: C_DOUBLE
real(C_DOUBLE):: accu_time
end function accu_time
function time_sys_sec() bind(C,name='time_sys_sec')
use, intrinsic:: ISO_C_BINDING, only: C_DOUBLE
real(C_DOUBLE):: time_sys_sec
end function time_sys_sec
function time_high_sec() bind(C,name='time_high_sec')
use, intrinsic:: ISO_C_BINDING, only: C_DOUBLE
real(C_DOUBLE):: time_high_sec
end function time_high_sec
end interface
contains
!---------------------------------------------------------
integer function timer_start(time_handle,time_set)
!This function sets up a timer limited to <time_set> seconds
!and returns its handle in <time_handle>.
implicit none
integer, intent(out):: time_handle !out: timer handle
real(8), intent(in):: time_set !in: requested time in seconds
real(8):: val
timer_start=TIMERS_SUCCESS; time_handle=-1
if(time_set.ge.0d0) then
!$OMP CRITICAL (TIMERS_REGION)
if(handle_sp.ge.0.and.handle_sp.lt.MAX_TIMERS) then
time_handle=handle_stack(handle_sp); handle_sp=handle_sp+1
else
timer_start=TIMERS_ERR_NO_TIMERS_LEFT
endif
!$OMP END CRITICAL (TIMERS_REGION)
if(timer_start.eq.TIMERS_SUCCESS) then
#ifndef NO_OMP
val=omp_get_wtime()
#else
call cpu_time(val)
#endif
timer(time_handle)=timer_t(val,time_set)
endif
else
timer_start=TIMERS_ERR_INVALID_ARG
endif
return
end function timer_start
!-------------------------------------------------------------------------
logical function timer_expired(time_handle,ierr,destroy,curr_time)
!This function tests whether a given timer has expired.
!If <destroy> is present and TRUE, timer handle will be destroyed if the timer has expired.
implicit none
integer, intent(inout):: time_handle !inout: timer handle
integer, intent(inout):: ierr !out: error code (0:success)
logical, intent(in), optional:: destroy !in: request to destroy the timer if it has expired
real(8), intent(out), optional:: curr_time !out: current timer value in seconds
real(8):: tm,ct
timer_expired=.FALSE.; ct=0d0
if(time_handle.ge.0.and.time_handle.lt.MAX_TIMERS) then !valid range
if(timer(time_handle)%time_interval.ge.0d0) then !valid handle
ierr=TIMERS_SUCCESS
#ifndef NO_OMP
tm=omp_get_wtime()
#else
call cpu_time(tm)
#endif
ct=tm-timer(time_handle)%beg_time
if(ct.ge.timer(time_handle)%time_interval) timer_expired=.TRUE.
if(timer_expired.and.present(destroy)) then
if(destroy) then
!$OMP CRITICAL (TIMERS_REGION)
timer(time_handle)=timer_t(-1d0,-1d0)
handle_sp=handle_sp-1; handle_stack(handle_sp)=time_handle
!$OMP END CRITICAL (TIMERS_REGION)
endif
endif
else
ierr=TIMERS_ERR_TIMER_NULL
endif
else
ierr=TIMERS_ERR_INVALID_ARG
endif
if(present(curr_time)) curr_time=ct
return
end function timer_expired
!---------------------------------------------------------
integer function timer_reset(time_handle,time_set)
!Resets an existing timer, regardless of its expiration status, to a new setting.
implicit none
integer, intent(inout):: time_handle !inout: timer handle
real(8), intent(in), optional:: time_set !in: requested time in seconds
real(8):: val
timer_reset=TIMERS_SUCCESS
if(time_handle.ge.0.and.time_handle.lt.MAX_TIMERS) then !valid range
if(timer(time_handle)%time_interval.ge.0d0) then !valid handle
#ifndef NO_OMP
val=omp_get_wtime()
#else
call cpu_time(val)
#endif
timer(time_handle)%beg_time=val
if(present(time_set)) then
if(time_set.ge.0d0) then
timer(time_handle)%time_interval=time_set
else
timer_reset=TIMERS_ERR_INVALID_ARG
endif
endif
!$OMP FLUSH
else
timer_reset=TIMERS_ERR_TIMER_NULL
endif
else
timer_reset=TIMERS_ERR_INVALID_ARG
endif
return
end function timer_reset
!--------------------------------------------------
integer function timer_destroy(time_handle)
!This function explicitly frees a timer handle.
implicit none
integer, intent(in):: time_handle
timer_destroy=TIMERS_SUCCESS
if(time_handle.ge.0.and.time_handle.lt.MAX_TIMERS) then !valid range
if(timer(time_handle)%time_interval.ge.0d0) then !valid handle
!$OMP CRITICAL (TIMERS_REGION)
timer(time_handle)=timer_t(-1d0,-1d0)
handle_sp=handle_sp-1; handle_stack(handle_sp)=time_handle
!$OMP END CRITICAL (TIMERS_REGION)
else
timer_destroy=TIMERS_ERR_TIMER_NULL
endif
else
timer_destroy=TIMERS_ERR_INVALID_ARG
endif
return
end function timer_destroy
!----------------------------------------
real(8) function timer_tick_sec()
!This function returns the wall clock tick length in seconds.
implicit none
#ifndef NO_OMP
!$OMP CRITICAL (TIMERS_REGION)
if(timer_tick.le.0d0) timer_tick=omp_get_wtick()
!$OMP END CRITICAL (TIMERS_REGION)
#endif
timer_tick_sec=timer_tick
return
end function timer_tick_sec
!-------------------------------------------
#ifndef NO_PHI
!DIR$ ATTRIBUTES OFFLOAD:mic:: thread_wtime
#endif
real(8) function thread_wtime(tbase)
!This function returns the current wall clock time in seconds;
!if <tbase> is present, since that moment.
implicit none
real(8), intent(in), optional:: tbase
real(8):: tm
#ifndef NO_OMP
thread_wtime=omp_get_wtime()
#else
#ifdef USE_GNU
thread_wtime=real(secnds(0.),8)
#else
call cpu_time(tm); thread_wtime=tm
#endif
#endif
if(present(tbase)) thread_wtime=thread_wtime-tbase
return
end function thread_wtime
end module timers