PROGRESS  master
prg_timer_mod.F90
Go to the documentation of this file.
1 
19 !
20 ! Timer routines.
21 !
22 
24 
26  use prg_extras_mod
27 
28  implicit none
29 
30  private
31 
32  integer, parameter :: dp = kind(1.0d0)
33 
34  public :: timer_status_t
35  public :: timer_prg_init
36  public :: prg_timer_shutdown
37  public :: prg_timer_start
38  public :: prg_timer_stop
39  public :: prg_timer_collect
40  public :: prg_timer_results
41  public :: time2milliseconds
42  public :: prg_print_date_and_time
43 
44  integer, public :: loop_timer, sp2_timer, genx_timer
46  integer, public :: ortho_timer, zdiag_timer, graphsp2_timer
47  integer, public :: subind_timer, subext_timer, subsp2_timer
48  integer, public :: suball_timer, bmult_timer, badd_timer
49  integer, public :: dyn_timer, mdloop_timer, buildz_timer
51  integer, public :: halfverlet_timer, pos_timer, nlist_timer
52 
55 
57  character(LEN=20) :: tname
58 
60  integer :: tstart
61 
63  integer :: ttotal
64 
66  integer :: tcount
67 
69  integer :: minrank
70 
72  integer :: maxrank
73 
75  real(dp):: tsum
76 
78  real(dp) :: minvalue
79 
81  real(dp) :: maxvalue
82 
84  real(dp) :: tavg
85 
87  real(dp) :: tstdev
88 
90  real(dp) :: tpercent
91 
92  end type timer_status_t
93 
94  !
95  ! Adding a new timer requires the following.
96  !
97  ! integer :: new_timer
98  !
99  ! In prg_init_timer, increment the timer count, specify a number
100  ! and name for the new timer.
101  !
102  ! ...
103  !
104  ! ! Increment when adding a new timer
105  ! num_timers = 4
106  !
107  ! ...
108  !
109  ! ! Timer handles, names, and counters
110  ! loop_timer = 1
111  ! sp2_timer = 2
112  ! genx_timer = 3
113  ! new_timer = 4
114  !
115  ! ptimer(loop_timer)%tname = "Loop"
116  ! ptimer(sp2_timer)%tname = " SP2"
117  ! ptimer(genx_timer)%tname = " GenX"
118  ! ptimer(new_timer)%tname = " New"
119  !
120 
122  integer :: num_timers
123 
124  type (timer_status_t), allocatable :: ptimer(:)
125 
126  private :: int2char
127 
128 contains
129 
131  subroutine timer_prg_init()
132 
133  integer :: i
134 
135  ! Increment when adding a new timer
136  num_timers = 24
137 
138  allocate(ptimer(num_timers))
139 
140  ! Timer handles, names, and counters
141  loop_timer = 1
142  subgraph_timer = 2
143  sp2_timer = 3
144  genx_timer = 4
145  part_timer = 5
146  deortho_timer = 6
147  ortho_timer = 7
148  zdiag_timer = 8
149  graphsp2_timer = 9
150  subind_timer = 10
151  subext_timer = 11
152  subsp2_timer = 12
153  suball_timer = 13
154  bmult_timer = 14
155  badd_timer = 15
156  dyn_timer = 16
157  mdloop_timer = 17
158  buildz_timer = 18
159  realcoul_timer = 19
160  recipcoul_timer = 20
161  pairpot_timer = 21
162  halfverlet_timer = 22
163  pos_timer = 23
164  nlist_timer = 24
165 
166  ptimer(loop_timer)%tname = "Loop"
167  ptimer(subgraph_timer)%tname = " Subgraph"
168  ptimer(sp2_timer)%tname = " SP2"
169  ptimer(genx_timer)%tname = " GenX"
170  ptimer(part_timer)%tname = " Part"
171  ptimer(deortho_timer)%tname = " Deortho"
172  ptimer(ortho_timer)%tname = " Ortho"
173  ptimer(zdiag_timer)%tname = " Zdiag"
174  ptimer(graphsp2_timer)%tname = " GraphSP2"
175  ptimer(subind_timer)%tname = " SubInd"
176  ptimer(subext_timer)%tname = " SubExt"
177  ptimer(subsp2_timer)%tname = " SubSP2"
178  ptimer(suball_timer)%tname = " SubAll"
179  ptimer(bmult_timer)%tname = " BMult"
180  ptimer(badd_timer)%tname = " BAdd"
181  ptimer(dyn_timer)%tname = " " !Reserved for dynamic timing
182  ptimer(mdloop_timer)%tname = "MDLoop"
183  ptimer(buildz_timer)%tname = " BuildZ"
184  ptimer(realcoul_timer)%tname = " RealCoul"
185  ptimer(recipcoul_timer)%tname = " RecipCoul"
186  ptimer(pairpot_timer)%tname = " PairPot"
187  ptimer(halfverlet_timer)%tname = " HalfVerlet"
188  ptimer(pos_timer)%tname = " Pos"
189  ptimer(nlist_timer)%tname = " NList"
190 
191  do i = 1, num_timers
192  ptimer(i)%ttotal = 0
193  ptimer(i)%tcount = 0
194  end do
195 
196  end subroutine timer_prg_init
197 
199  subroutine prg_timer_getid()
200 
201  end subroutine prg_timer_getid
202 
204  subroutine prg_timer_shutdown()
205 
206  if(allocated(ptimer))deallocate(ptimer)
207 
208  end subroutine prg_timer_shutdown
209 
214  subroutine prg_timer_start(itimer,tag)
215 
216  integer, intent(in) :: itimer
217  character(len=*), intent(in), optional :: tag
218 
219  if(present(tag))then
220  ptimer(itimer)%tname = tag
221  endif
222 
223  call system_clock(tstart_clock, tclock_rate, tclock_max)
224  ptimer(itimer)%tstart = tstart_clock
225 
226  end subroutine prg_timer_start
227 
232  subroutine prg_timer_stop(itimer,verbose)
233 
234  integer, intent(in) :: itimer
235  integer :: tprg_delta
236  integer, intent(in), optional :: verbose
237 
238  call system_clock(tstop_clock, tclock_rate, tclock_max)
239  tprg_delta = tstop_clock - ptimer(itimer)%tstart
240  if(present(verbose))then
241  if(verbose.gt.0)then
242  write(*,*)"Time for "//trim(ptimer(itimer)%tname)//" = "//to_string(tprg_delta)//" ms"
243  endif
244  endif
245  ptimer(itimer)%ttotal = ptimer(itimer)%ttotal + tprg_delta
246  ptimer(itimer)%tcount = ptimer(itimer)%tcount + 1
247 
248  end subroutine prg_timer_stop
249 
250  ! Collect timer results
251  !
252  subroutine prg_timer_collect()
253 
254  integer :: i
255  real(dp) :: temp
256  real(dp), allocatable :: sendbuf(:), recvbuf(:)
257  type(rankreducedata_t), allocatable :: reducesendbuf(:)
258  type(rankreducedata_t), allocatable :: reducerecvbuf(:)
259 
260  real(dp) :: rranks
261 
262  allocate(sendbuf(num_timers))
263  allocate(recvbuf(num_timers))
264 
265  rranks = float(getnranks())
266 
267  !! Determine average of each timer across ranks
268  do i = 1, num_timers
269  sendbuf(i) = float(ptimer(i)%ttotal)/float(tclock_rate)
270  enddo
271  call sumrealparallel(sendbuf, recvbuf, num_timers);
272 
273  do i = 1, num_timers
274  ptimer(i)%tavg = recvbuf(i) / rranks
275  enddo
276 
277  !! Determine min and max across ranks and which rank
278  allocate(reducesendbuf(num_timers))
279  allocate(reducerecvbuf(num_timers))
280 
281  do i = 1, num_timers
282  reducesendbuf(i)%val = float(ptimer(i)%ttotal)/float(tclock_rate)
283  reducesendbuf(i)%rank = getmyrank()
284  enddo
285  call minrankrealparallel(reducesendbuf, reducerecvbuf, num_timers);
286  do i = 1, num_timers
287  ptimer(i)%minValue = reducerecvbuf(i)%val
288  ptimer(i)%minRank = reducerecvbuf(i)%rank
289  enddo
290  call maxrankrealparallel(reducesendbuf, reducerecvbuf, num_timers);
291  do i = 1, num_timers
292  ptimer(i)%maxValue = reducerecvbuf(i)%val
293  ptimer(i)%maxRank = reducerecvbuf(i)%rank
294  enddo
295 
296  deallocate(reducesendbuf)
297  deallocate(reducerecvbuf)
298 
299  !! Determine standard deviation
300  do i = 1, num_timers
301  temp = float(ptimer(i)%ttotal)/float(tclock_rate) - ptimer(i)%tavg
302  sendbuf(i) = temp * temp;
303  enddo
304  call sumrealparallel(sendbuf, recvbuf, num_timers);
305  do i = 1, num_timers
306  ptimer(i)%tstdev = sqrt(recvbuf(i) / rranks)
307  enddo
308 
309  deallocate(sendbuf)
310  deallocate(recvbuf)
311 
312  end subroutine prg_timer_collect
313 
314  ! Print performance results
315  !
316  subroutine prg_timer_results()
317 
318  integer :: i
319 
320  ! Collect results across all ranks
321  call prg_timer_collect()
322 
323  ! Print timer results
324  if (printrank() .eq. 1) then
325 
326  write(*,*) ""
327  write(*,*) "Timings for Rank ", getmyrank()
328  write(*,*) "Timer # Calls Avg/Call (s) Total (s) % Time"
329  write(*,*) ""
330 
331  do i = 1, num_timers
332  if (ptimer(i)%tcount .gt. 0) then
333  !! ptimer(i)%tavg = (float(ptimer(i)%ttotal)/float(tclock_rate))/float(ptimer(i)%tcount)
334  ptimer(i)%tsum = float(ptimer(i)%ttotal)/float(tclock_rate)
335  ptimer(i)%tpercent = (ptimer(i)%tsum / ptimer(1)%tsum) * 100.0
336  write(*,10) ptimer(i)%tname, ptimer(i)%tcount, ptimer(i)%tsum/float(ptimer(i)%tcount), ptimer(i)%tsum, ptimer(i)%tpercent
337 10 format(a23, i6, 3g16.6)
338  end if
339  end do
340 
341  write(*,*) ""
342  write(*,*) "Timing Statistics Across ", getnranks(), " Ranks:"
343  write(*,*) "Timer Rank: Min(s) Rank: Max(s) Avg(s) Stdev(s)"
344  write(*,*)
345 
346  do i = 1, num_timers
347  if (ptimer(i)%tcount > 0) then
348  write(*, 20) ptimer(i)%tname, &
349  ptimer(i)%minRank, ptimer(i)%minValue, &
350  ptimer(i)%maxRank, ptimer(i)%maxValue, &
351  ptimer(i)%tavg, ptimer(i)%tstdev
352 20 format(a23,2x,i4,g16.6,i4,3g16.6)
353  endif
354  enddo
355  endif
356 
357  end subroutine prg_timer_results
358 
359  function time2milliseconds() result(mls)
360 
361  real(8) :: mls
362  integer :: timevector(8)
363 
364  call date_and_time(values=timevector)
365  mls = timevector(5)*60*60*1000 + timevector(6)*60*1000 + &
366  timevector(7)*1000 + timevector(8)
367 
368  end function time2milliseconds
369 
370  subroutine prg_print_date_and_time(tag)
371 
372  implicit none
373 
374  character(len=*), intent(in) :: tag
375  character(2) :: monthchar, daychar,hourchar,minchar,secchar
376  integer :: sec, mins, hour, day, month, year
377  integer :: timevector(8)
378 
379  call date_and_time(values=timevector)
380 
381  year = timevector(1); month = timevector(2); day = timevector(3)
382  hour = timevector(5); mins = timevector(6); sec = timevector(7)
383 
384  monthchar = int2char(month); daychar = int2char(day)
385  hourchar = int2char(hour); minchar = int2char(mins); secchar = int2char(sec)
386 
387  write(*,'(a2,a,x,A2,a1,A2,a1,i4,x,a2,x,A2,a1,A2,a1,A2)')"# ", &
388  trim(tag),monthchar,"/" &
389  ,daychar,"/",year, "at", hourchar,":",minchar,":",secchar
390 
391  end subroutine prg_print_date_and_time
392 
393  function int2char(ival)
394 
395  implicit none
396 
397  integer, intent(in) :: ival
398  character(2) :: int2char, myintchar
399 
400  if ((ival/10) .lt. 1) then
401  write(myintchar,'(I2)') ival
402  myintchar="0"//trim(adjustl(myintchar))
403  else
404  write(myintchar,'(I2)') ival
405  endif
406 
407  int2char = myintchar
408 
409  end function int2char
410 
411 end module prg_timer_mod
Extra routines.
real(dp) function, public mls()
To get the actual time in milliseconds.
integer, parameter dp
The parallel module.
subroutine, public maxrankrealparallel(sendBuf, recvBuf, icount)
subroutine, public minrankrealparallel(sendBuf, recvBuf, icount)
subroutine, public sumrealparallel(sendBuf, recvBuf, icount)
integer function, public printrank()
integer function, public getnranks()
integer function, public getmyrank()
The timer module.
integer, public loop_timer
integer, public badd_timer
integer, public dyn_timer
subroutine, public prg_print_date_and_time(tag)
integer, public nlist_timer
subroutine, public prg_timer_results()
subroutine, public prg_timer_shutdown()
Done with timers.
real(8) function, public time2milliseconds()
subroutine, public timer_prg_init()
Initialize timers.
subroutine, public prg_timer_start(itimer, tag)
Start Timing.
integer, public part_timer
integer, public sp2_timer
integer, public subind_timer
integer, public zdiag_timer
integer, public subext_timer
integer, public pairpot_timer
subroutine prg_timer_getid()
Get timer id.
subroutine, public prg_timer_stop(itimer, verbose)
Stop timing.
integer, public mdloop_timer
integer, public ortho_timer
integer, public halfverlet_timer
integer, public buildz_timer
integer, public pos_timer
integer, public bmult_timer
integer, public genx_timer
integer, public subgraph_timer
integer, public graphsp2_timer
type(timer_status_t), dimension(:), allocatable ptimer
integer, public suball_timer
integer, public realcoul_timer
integer tstart_clock
integer, public deortho_timer
integer, public subsp2_timer
integer, public recipcoul_timer
subroutine, public prg_timer_collect()
character(2) function, private int2char(ival)
Data structure for rection over MPI ranks.