Branch data Line data Source code
1 : : !!****m* ABINIT/m_time
2 : : !! NAME
3 : : !! m_time
4 : : !!
5 : : !! FUNCTION
6 : : !! This module contains accumulators for the timer.
7 : : !! and functions to get cpu and wall time.
8 : : !!
9 : : !! COPYRIGHT
10 : : !! Copyright (C) 2009-2026 ABINIT group (MG, XG, MT, TD)
11 : : !! This file is distributed under the terms of the
12 : : !! GNU General Public License, see ~abinit/COPYING
13 : : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : : !!
15 : :
16 : : #if defined HAVE_CONFIG_H
17 : : #include "config.h"
18 : : #endif
19 : :
20 : : #include "abi_common.h"
21 : :
22 : : module m_time
23 : :
24 : : use defs_basis
25 : : use m_abicore
26 : : use m_errors
27 : : use, intrinsic :: iso_c_binding
28 : : USE_MPI
29 : : use m_xmpi
30 : : use m_clib
31 : :
32 : : use m_xpapi, only: xpapi_flops
33 : : use m_fstrings, only: char_count, sjoin
34 : :
35 : : implicit none
36 : :
37 : : #if defined HAVE_MPI1
38 : : include 'mpif.h'
39 : : #endif
40 : :
41 : : private
42 : :
43 : : public :: asctime ! Build a 24-character string of the following form: 'Sun Jun 20 23:21:05 1993'.
44 : : public :: sec2str ! Convert time data in seconds to string
45 : : public :: str2sec ! Convert a string with time (Slurm form) in seconds
46 : : public :: abi_wtime ! Returns wall clock time in seconds since some arbitrary start.
47 : : public :: abi_cpu_time ! Returns cpu time in seconds since some arbitrary start.
48 : : public :: cwtime ! Returns cpu, wall clock time and gflops
49 : : public :: cwtime_report ! Stop timers, write message, reinit counters.
50 : :
51 : : ! FIXME: Deprecated Should be replaced by cwtime
52 : : public :: timein
53 : : public :: time_accu
54 : : public :: timab
55 : : public :: time_set_papiopt
56 : : public :: time_get_papiopt
57 : :
58 : : !!***
59 : :
60 : : ! papiopt is a flag which indicates if there is or not an analysis of speed execution is made.
61 : : ! By defaut the analysis is not done
62 : : integer,private,save :: papiopt=0
63 : :
64 : : !==================
65 : : ! Counter variables
66 : : !==================
67 : :
68 : : ! TIMER_SIZE determines the maximum number of "timing slots" available
69 : : integer,public,parameter :: TIMER_SIZE=2199
70 : :
71 : : ! timeopt is a flag which indicates the suppression or not of the timing.
72 : : integer,private,save :: timopt=1
73 : :
74 : : ! Number of times that the routine has been called
75 : : integer,private,save :: ncount(TIMER_SIZE)=0
76 : :
77 : : ! Accumulating cpu time (1) and wall to wall time (2) for each "timing slots"
78 : : real(dp),private,save :: acctim(2,TIMER_SIZE)=zero,tzero(2,TIMER_SIZE)=zero
79 : :
80 : : ! Accumulating number of floating point operation and cpu time (1) and wall time (2) for each "performance slot"
81 : : real(dp),private,save :: papi_accflops(TIMER_SIZE)=zero, papi_acctim(2,TIMER_SIZE)=zero
82 : :
83 : : ! Reference value for number of floating point operation and time (cpu and wall) for each performance slot
84 : : real(dp),private,save :: papi_flops(TIMER_SIZE)=zero , papi_tzero(2,TIMER_SIZE)=zero
85 : :
86 : : ! Elapsed time and elapsed number of floating point operation since a reference
87 : : #ifdef HAVE_PAPI
88 : : real(dp),private,save :: papi_tottim(2,TIMER_SIZE)=zero, papi_totflops(TIMER_SIZE)=zero
89 : : #endif
90 : :
91 : : CONTAINS
92 : : !!***
93 : :
94 : : !!****f* m_time/asctime
95 : : !! NAME
96 : : !! asctime
97 : : !!
98 : : !! FUNCTION
99 : : !! Build a 24-character string of the following form: 'Sun Jun 20 23:21:05 1993'.
100 : : !!
101 : : !! SOURCE
102 : :
103 : 7608 : function asctime()
104 : :
105 : : !Arguments ------------------------------------
106 : : character(len=24) :: asctime
107 : :
108 : : !Local variables-------------------------------
109 : : integer :: day,dd,ja,jy,jm,jdn,mm,year
110 : : integer :: values(8)
111 : : character(len=5) :: strzone
112 : : character(len=8) :: strdat
113 : : character(len=10) :: strtime
114 : : character(len=3),parameter :: day_names(7)=(/'Mon','Tue','Wed','Thu','Fri','Sat','Sun'/)
115 : : character(len=3),parameter :: month_names(12)=(/'Jan','Feb','Mar','Apr','May','Jun',&
116 : : & 'Jul','Aug','Sep','Oct','Nov','Dec'/)
117 : : ! *************************************************************************
118 : :
119 : : !Get year, month and day
120 : 7608 : call date_and_time(strdat,strtime,strzone,values)
121 : :
122 : 7608 : year=values(1)
123 : 7608 : mm=values(2)
124 : 7608 : dd=values(3)
125 : :
126 : : !Get day of the week
127 [ + - ]: 7608 : if (mm > 2) then
128 : 7608 : jy=year
129 : 7608 : jm=mm+1
130 : : else
131 : 0 : jy=year-1
132 : 0 : jm=mm+13
133 : : end if
134 : :
135 : 7608 : jdn=int(365.25d0*jy)+int(30.6001d0*jm)+dd+1720995
136 : 7608 : ja=int(0.01d0*jy)
137 : 7608 : jdn=jdn+2-ja+int(quarter*ja)
138 : 7608 : day=mod(jdn,7)+1
139 : :
140 : : ! Build a 24-character string of the following form: 'Sun Jun 20 23:21:05 1993'.
141 : : write(asctime, '(a,1x,a,1x,i0.2,1x,2(i0.2,a),i0.2,1x,i4)')&
142 : 7608 : day_names(day),month_names(mm),dd,values(5),":",values(6),":",values(7),year
143 : :
144 : 7608 : end function asctime
145 : : !!***
146 : :
147 : : !----------------------------------------------------------------------
148 : :
149 : : !!****f* m_time/sec2str
150 : : !! NAME
151 : : !! sec2str
152 : : !!
153 : : !! FUNCTION
154 : : !! Convert time data in seconds to string
155 : : !!
156 : : !! INPUTS
157 : : !! time_s=Time in seconds
158 : : !!
159 : : !! OUTPUT
160 : : !! string with time displayed in the form: [days-][hours:][minutes:]seconds
161 : : !!
162 : : !! SOURCE
163 : :
164 : 176420 : pure function sec2str(time_s) result(str)
165 : :
166 : : !Arguments ------------------------------------
167 : : !scalars
168 : : real(dp),intent(in) :: time_s
169 : : character(len=500) :: str
170 : :
171 : : !Local variables-------------------------------
172 : : integer :: days,hours,minutes,seconds
173 : : ! *************************************************************************
174 : :
175 : 176420 : days = time_s / 86400
176 : 176420 : hours = MOD(time_s,86400._dp) / 3600
177 : 176420 : minutes = MOD(time_s,3600._dp) / 60
178 : 176420 : seconds = MOD(time_s,60._dp)
179 : :
180 [ - + ]: 176420 : if (days > 0) then
181 : 0 : write(str,'(i0,3(a,i0.2),a)')days,"-",hours,":",minutes,":",seconds, " [days]"
182 [ + + ]: 176420 : else if (hours > 0) then
183 : 5 : write(str,'(i0.2,2(a,i0.2),a)')hours,":",minutes,":",seconds, " [hours]"
184 [ + + ]: 176415 : else if (minutes > 0) then
185 : 63 : write(str,'(i0.2,a,i0.2,a)')minutes,":",seconds, " [minutes]"
186 : : else
187 : 176352 : write(str,'(f5.2,a)')time_s," [s]"
188 : : end if
189 : :
190 : 176420 : end function sec2str
191 : : !!***
192 : :
193 : : !----------------------------------------------------------------------
194 : :
195 : : !!****f* m_time/str2sec
196 : : !! NAME
197 : : !! str2sec
198 : : !!
199 : : !! FUNCTION
200 : : !! Convert a string to time data in seconds. Return negative value if not valid string
201 : : !! Accepts a string in one the following (SLURM) forms:
202 : : !!
203 : : !! # "days-hours",
204 : : !! # "days-hours:minutes",
205 : : !! # "days-hours:minutes:seconds".
206 : : !! # "minutes",
207 : : !! # "minutes:seconds",
208 : : !! # "hours:minutes:seconds",
209 : : !!
210 : : !! SOURCE
211 : :
212 : 4 : real(dp) pure function str2sec(str) result(time)
213 : :
214 : : !Arguments ------------------------------------
215 : : !scalars
216 : : character(len=*),intent(in) :: str
217 : :
218 : : !Local variables-------------------------------
219 : : integer :: days,hours,minutes,seconds,dash,i,j
220 : : ! *************************************************************************
221 : :
222 : 4 : days = 0; hours = 0; minutes = 0; seconds = 0
223 : 4 : dash = index(str, "-")
224 [ - + - - ]: 4 : if (dash /= 0) read(str(:dash-1),*,err=1) days
225 : :
226 : 0 : select case (char_count(str, ":"))
227 : : case (0)
228 [ # # ]: 0 : if (dash /= 0) then
229 [ # # ]: 0 : read(str(dash+1:),*,err=1)hours
230 : : else
231 [ # # ]: 0 : read(str(dash+1:),*,err=1)minutes
232 : : end if
233 : :
234 : : case (1)
235 : 0 : i = index(str, ":")
236 [ # # ]: 0 : if (dash /= 0) then
237 [ # # ]: 0 : read(str(dash+1:i-1),*,err=1)hours
238 [ # # ]: 0 : read(str(i+1:),*,err=1)minutes
239 : : else
240 [ # # ]: 0 : read(str(:i-1),*,err=1)minutes
241 [ # # ]: 0 : read(str(i+1:),*,err=1)seconds
242 : : end if
243 : :
244 : : case(2)
245 : 4 : i = index(str, ":")
246 [ + - ]: 4 : read(str(dash+1:i-1),*,err=1)hours
247 : 4 : j = index(str(i+1:), ":") + i
248 [ + - ]: 4 : read(str(i+1:j-1),*,err=1)minutes
249 [ + - ]: 4 : read(str(j+1:),*,err=1)seconds
250 : :
251 : : case default
252 [ - - - + ]: 4 : time = -one; return
253 : : end select
254 : :
255 : 4 : time = 24 * 3600 * days + hours * 3600 + minutes * 60 + seconds
256 : 4 : return
257 : :
258 : : 1 time = -one
259 : :
260 : : end function str2sec
261 : : !!***
262 : :
263 : : !----------------------------------------------------------------------
264 : :
265 : : !!****f* m_time/abi_cpu_time
266 : : !! NAME
267 : : !! abi_cpu_time
268 : : !!
269 : : !! FUNCTION
270 : : !! Timing routine. Returns cpu time in seconds since some arbitrary start.
271 : : !!
272 : : !! INPUTS
273 : : !! (no inputs)
274 : : !!
275 : : !! OUTPUT
276 : : !! cpu_time= cpu time in seconds
277 : : !!
278 : : !! NOTES
279 : : !! For CPU time, contains machine-dependent code (choice will be selected by c preprocessor).
280 : : !! Note that all supported machines are listed explicitly below; there
281 : : !! is no "else" which covers "other". The C preprocessor will place
282 : : !! a spurious line of code (see below) into the fortran source unless
283 : : !! preprocessed with -Dflag where flag refers to one of the supported machines.
284 : : !!
285 : : !! WARNING: the following list is no more accurate (YP 20060530)
286 : : !!
287 : : !! Presently supported flags: "ibm", "hp", "P6", "dec_alpha", "sgi", "vpp", "sun", "mac", "nec", "sr8k"
288 : : !! Previously supported flags: "ultrix". Might still work !
289 : : !!
290 : : !! Calls machine-dependent "mclock" for "ibm" .
291 : : !! Calls ANSI C subroutine "cclock" for "hp" and "sgi".
292 : : !! Calls machine-dependent "etime" for "P6", "mac", "dec_alpha", "sun", "nec" .
293 : : !! Calls machine-dependent "clock" for "vpp"
294 : : !! Calls machine-dependent "xclock" for "sr8k"
295 : : !!
296 : : !! SOURCE
297 : :
298 : 68275525 : function abi_cpu_time() result(cpu)
299 : :
300 : : !Arguments ------------------------------------
301 : : real(dp) :: cpu
302 : :
303 : : !Local variables-------------------------------
304 : : #ifdef HAVE_FC_CPUTIME
305 : : real :: cpu_sp
306 : : #elif defined FC_IBM
307 : : integer :: mclock
308 : : #elif defined HAVE_OS_MACOSX
309 : : real :: tmp(2) !real array only needed by etime
310 : : real(dp) :: etime
311 : : #else
312 : : integer :: count_now,count_max,count_rate
313 : : #endif
314 : : ! *************************************************************************
315 : :
316 : : !Machine-dependent timers
317 : : #ifdef HAVE_CCLOCK
318 : : call clib_cclock(cpu)
319 : :
320 : : #elif defined HAVE_FC_CPUTIME
321 : : !This is the F95 standard subroutine.
322 : 1290850 : call cpu_time(cpu_sp)
323 : 68275525 : cpu = cpu_sp
324 : :
325 : : #elif defined FC_IBM
326 : : cpu = mclock()*0.01d0
327 : :
328 : : #elif defined HAVE_OS_MACOSX
329 : : cpu = clib_etime(tmp)
330 : :
331 : : #else
332 : : !This is the Fortran90 standard subroutine, might not always be sufficiently accurate
333 : : call system_clock(count_now,count_rate,count_max)
334 : : cpu=dble(count_now)/dble(count_rate)
335 : : #endif
336 : :
337 : 0 : end function abi_cpu_time
338 : : !!***
339 : :
340 : : !----------------------------------------------------------------------
341 : :
342 : : !!****f* m_time/abi_wtime
343 : : !! NAME
344 : : !! abi_wtime
345 : : !!
346 : : !! FUNCTION
347 : : !! Return wall clock time in seconds since some arbitrary start.
348 : : !! Call the F90 intrinsic date_and_time .
349 : : !!
350 : : !! INPUTS
351 : : !! (no inputs)
352 : : !!
353 : : !! OUTPUT
354 : : !! wall= wall clock time in seconds
355 : : !!
356 : : !! SOURCE
357 : :
358 : 69987720 : function abi_wtime() result(wall)
359 : :
360 : : !Arguments ------------------------------------
361 : : !scalars
362 : : real(dp) :: wall
363 : :
364 : : !Local variables-------------------------------
365 : : !scalars
366 : : #ifndef HAVE_MPI
367 : : integer,parameter :: nday(24)=(/31,28,31,30,31,30,31,31,30,31,30,31,&
368 : : & 31,28,31,30,31,30,31,31,30,31,30,31/)
369 : : integer,save :: month_init,month_now,start=1,year_init
370 : : integer :: months
371 : : character(len=8) :: date
372 : : character(len=10) :: time
373 : : character(len=5) :: zone
374 : : character(len=500) :: msg
375 : : !arrays
376 : : integer :: values(8)
377 : : #endif
378 : : ! *************************************************************************
379 : :
380 : : #ifndef HAVE_MPI
381 : :
382 : : !The following section of code is standard F90, but it is useful only if the intrinsics
383 : : !date_and_time is accurate at the 0.01 sec level, which is not the case for a P6 with the pghpf compiler ...
384 : : !Year and month initialisation
385 : : if(start==1)then
386 : : start=0
387 : : call date_and_time(date,time,zone,values)
388 : : year_init=values(1)
389 : : month_init=values(2)
390 : : end if
391 : :
392 : : !Uses intrinsic F90 subroutine Date_and_time for
393 : : !wall clock (not correct when a change of year happen)
394 : : call date_and_time(date,time,zone,values)
395 : :
396 : : !Compute first the number of seconds from the beginning of the month
397 : : wall=(values(3)*24.0d0+values(5))*3600.0d0+values(6)*60.0d0+values(7)+values(8)*0.001d0
398 : :
399 : : !If the month has changed, compute the number of seconds
400 : : !to be added. This fails if the program ran one year !!
401 : : month_now=values(2)
402 : : if(month_now/=month_init)then
403 : : if(year_init+1==values(1))then
404 : : month_now=month_now+12
405 : : end if
406 : : if(month_now<=month_init)then
407 : : msg = 'Problem with month and year numbers.'
408 : : ABI_BUG(msg)
409 : : end if
410 : : do months=month_init,month_now-1
411 : : wall=wall+86400.0d0*nday(months)
412 : : end do
413 : : end if
414 : :
415 : : !Now take into account bissextile years (I think 2000 is bissextile, but I am not sure ...)
416 : : if(mod(year_init,4)==0 .and. month_init<=2 .and. month_now>2) wall=wall+3600.0d0
417 : : if(mod(values(1),4)==0 .and. month_init<=14 .and. month_now>14) wall=wall+3600.0d0
418 : :
419 : : #else
420 : : !Use the timer provided by MPI1.
421 : 1712195 : wall = MPI_WTIME()
422 : : #endif
423 : :
424 : 1712195 : end function abi_wtime
425 : : !!***
426 : :
427 : : !----------------------------------------------------------------------
428 : :
429 : : !!****f* m_time/cwtime
430 : : !! NAME
431 : : !! cwtime
432 : : !!
433 : : !! FUNCTION
434 : : !! Timing routine. Returns cpu and wall clock time in seconds.
435 : : !!
436 : : !! INPUTS
437 : : !! start_or_stop=
438 : : !! "start" to start the timers
439 : : !! "stop" to stop the timers and return the final cpu_time and wall_time
440 : : !! [msg]: Optional message printed to std_out
441 : : !! [comm]: MPI communicator. If values averaged inside comm are wanted. Only for "stop"
442 : : !!
443 : : !! OUTPUT
444 : : !! cpu= cpu time in seconds
445 : : !! wall= wall clock time in seconds
446 : : !! gflops = Gigaflops
447 : : !!
448 : : !! NOTES
449 : : !! Example:
450 : : !! ! Init cpu and wall
451 : : !! call cwtime(cpu,wall,gflops,"start")
452 : : !!
453 : : !! do_stuff()
454 : : !!
455 : : !! ! stop the counters, return cpu- and wall-time spent in do_stuff()
456 : : !! call cwtime(cpu,wall,gflops,"stop")
457 : : !!
458 : : !! SOURCE
459 : :
460 : 1290850 : subroutine cwtime(cpu, wall, gflops, start_or_stop, msg, comm)
461 : :
462 : : !Arguments ------------------------------------
463 : : !scalars
464 : : real(dp),intent(inout) :: cpu,wall
465 : : real(dp),intent(out) :: gflops
466 : : character(len=*),intent(in) :: start_or_stop
467 : : character(len=*),intent(in),optional :: msg
468 : : integer,intent(in),optional :: comm
469 : :
470 : : !Local variables-------------------------------
471 : : #ifndef HAVE_PAPI
472 : : logical,parameter :: use_papi=.FALSE.
473 : : #else
474 : : logical,parameter :: use_papi=.TRUE.
475 : : #endif
476 : : integer :: ierr
477 : : integer(C_INT) :: check
478 : : integer(C_LONG_LONG) :: flops
479 : : real(C_FLOAT) :: real_time,proc_time,mflops
480 : : real(dp) :: vals(3)
481 : : ! *************************************************************************
482 : :
483 [ + + ]: 1290850 : if (present(msg)) call wrtout(std_out, msg)
484 : :
485 : : select case (start_or_stop)
486 : : case ("start")
487 : 739609 : if (use_papi) then
488 : : call xpapi_flops(real_time,proc_time,flops,mflops,check)
489 : : cpu = proc_time; wall = real_time; gflops = mflops / 1000
490 : : else
491 : 739609 : cpu = abi_cpu_time(); wall = abi_wtime(); gflops = -one
492 : : end if
493 : :
494 : : case ("stop")
495 : : if (use_papi) then
496 : : call xpapi_flops(real_time,proc_time,flops,mflops,check)
497 : : cpu = proc_time - cpu; wall = real_time - wall; gflops = mflops / 1000
498 : : else
499 : 551241 : cpu = abi_cpu_time() - cpu; wall = abi_wtime() - wall; gflops = -one
500 : : end if
501 [ + + ]: 551241 : if (present(comm)) then
502 [ + + ]: 980 : vals = [cpu, wall, gflops]
503 : 245 : call xmpi_sum(vals, comm, ierr)
504 [ + + ]: 980 : vals = vals / xmpi_comm_size(comm)
505 : 245 : cpu = vals(1); wall = vals(2); gflops = vals(3)
506 : : end if
507 : :
508 : : case default
509 [ + + - - : 1290850 : ABI_ERROR("Wrong option for start_or_stop: "//trim(start_or_stop))
- ]
510 : : end select
511 : :
512 : 1290850 : end subroutine cwtime
513 : : !!***
514 : :
515 : : !----------------------------------------------------------------------
516 : :
517 : : !!****f* m_time/cwtime_report
518 : : !! NAME
519 : : !! cwtime_report
520 : : !!
521 : : !! FUNCTION
522 : : !! Stop timers, write message, reinit counters.
523 : : !!
524 : : !! INPUT
525 : : !! [pre_str], [end_str]: String to print before and after the timing section
526 : : !! [comm]: MPI communicator. If values averaged inside comm is wanted. Only for "stop"
527 : : !!
528 : : !! SIDE EFFECTS
529 : : !! cpu= cpu time in seconds
530 : : !! wall= wall clock time in seconds
531 : : !! gflops = Gigaflops
532 : : !!
533 : : !! OUTPUT
534 : : !! [out_wall]= Output wall-time.
535 : : !!
536 : : !! SOURCE
537 : :
538 : 113250 : subroutine cwtime_report(tag, cpu, wall, gflops, pre_str, end_str, out_wall, comm)
539 : :
540 : : !Arguments ------------------------------------
541 : : !scalars
542 : : real(dp),intent(inout) :: cpu,wall
543 : : real(dp),intent(out) :: gflops
544 : : integer,intent(in),optional :: comm
545 : : character(len=*),intent(in) :: tag
546 : : character(len=*),optional,intent(in) :: pre_str, end_str
547 : : real(dp),optional,intent(out) :: out_wall
548 : :
549 : : !Local variables-------------------------------
550 : : character(len=500) :: avg_type
551 : : ! *************************************************************************
552 : :
553 [ + + ]: 56625 : if (present(comm)) then
554 : 245 : call cwtime(cpu, wall, gflops, "stop", comm=comm)
555 : 245 : avg_type = "(MPI average) <<< TIME"
556 : : else
557 : 56380 : call cwtime(cpu, wall, gflops, "stop")
558 : 56380 : avg_type = "<<< TIME"
559 : : end if
560 [ + + ]: 56625 : if (present(pre_str)) call wrtout(std_out, pre_str)
561 : :
562 : 56625 : call wrtout(std_out, sjoin(tag, ", wall:", sec2str(wall), ", cpu:", sec2str(cpu), avg_type), do_flush=.True.)
563 : :
564 : : !if (present(end_str)) call wrtout(std_out, " ...")
565 [ + + ]: 56625 : if (present(end_str)) call wrtout(std_out, end_str)
566 [ + + ]: 56625 : if (present(out_wall)) out_wall = wall
567 : :
568 : 56625 : call cwtime(cpu, wall, gflops, "start")
569 : :
570 : : ! Activate this line to get mallinfo section for each checkpoint
571 : : !call clib_print_mallinfo(std_out)
572 : :
573 : 56625 : end subroutine cwtime_report
574 : : !!***
575 : :
576 : : !!****f* m_time/timein
577 : : !! NAME
578 : : !! timein
579 : : !!
580 : : !! FUNCTION
581 : : !! Timing routine. Returns cpu and wall clock time in seconds since some arbitrary start.
582 : : !! For wall clock time, call the F90 intrinsic date_and_time.
583 : : !!
584 : : !! INPUTS
585 : : !! (no inputs)
586 : : !!
587 : : !! OUTPUT
588 : : !! cpu= cpu time in seconds
589 : : !! wall= wall clock time in seconds
590 : : !!
591 : : !! NOTES
592 : : !! For CPU time, contains machine-dependent code (choice will be selected
593 : : !! by C preprocessor, see abi_cpu_time).
594 : : !!
595 : : !! TODO
596 : : !! Should be replaced by cwtime
597 : : !!
598 : : !! SOURCE
599 : :
600 : 66984675 : subroutine timein(cpu,wall)
601 : :
602 : : !Arguments ------------------------------------
603 : : real(dp),intent(out) :: cpu,wall
604 : : ! *************************************************************************
605 : :
606 : : ! CPU time
607 : 66984675 : cpu = abi_cpu_time()
608 : : ! Wall time
609 : 66984675 : wall = abi_wtime()
610 : :
611 : 66984675 : end subroutine timein
612 : : !!***
613 : :
614 : : !!****f* m_time/time_accu
615 : : !! NAME
616 : : !! time_accu
617 : : !!
618 : : !! FUNCTION
619 : : !! Return the number of times the counter has been called
620 : : !! and corresponding data for given index
621 : : !!
622 : : !! INPUTS
623 : : !! nn=index of accumulator (distinguish what is being timed);
624 : : !!
625 : : !! OUTPUT
626 : : !! tottim(2)=accumulated time for accumulator nn
627 : : !! totftimes(2)=accumulated time for accumulator nn evaluated by papi
628 : : !! totffops =accumulated number of flops for accumulator nn evaluated by papi
629 : : !! return_ncount gives the number of times that the accumulator has been incremented
630 : : !!
631 : : !! SOURCE
632 : :
633 : 277817 : subroutine time_accu(nn,return_ncount,tottim,totflops,totftimes)
634 : :
635 : : !Arguments ------------------------------------
636 : : !scalars
637 : : integer,intent(in) :: nn
638 : : integer,intent(out) :: return_ncount
639 : : real(dp),intent(out) :: totflops
640 : : !arrays
641 : : real(dp),intent(out) :: totftimes(2),tottim(2)
642 : :
643 : : !Local variables-------------------------------
644 : : !scalars
645 : : character(len=500) :: msg
646 : : ! *************************************************************************
647 : :
648 : : ! Check that nn lies in sensible bounds
649 [ - + ]: 277817 : if (nn<0.or.nn>TIMER_SIZE) then
650 : 0 : write(msg,'(a,i0,a,i0,a)')' dim TIMER_SIZE=',TIMER_SIZE,' but input nn=',nn,'.'
651 : 0 : ABI_BUG(msg)
652 : : end if
653 : :
654 : : !return accumulated time for nn
655 : 277817 : tottim(1)=acctim(1,nn)
656 : 277817 : tottim(2)=acctim(2,nn)
657 : :
658 : : !return accumulated number flops for nn
659 : 277817 : totflops = papi_accflops(nn)
660 : :
661 : : !return accumulated time for nn evaluated by papi
662 : 277817 : totftimes(1) = papi_acctim(1,nn)
663 : 277817 : totftimes(2) = papi_acctim(2,nn)
664 : 277817 : return_ncount=ncount(nn)
665 : :
666 : 277817 : end subroutine time_accu
667 : : !!***
668 : :
669 : : !!****f* m_time/time_set_papiopt
670 : : !! NAME
671 : : !! time_set_papiopt
672 : : !!
673 : : !! FUNCTION
674 : : !! Set the value of papiopt
675 : : !!
676 : : !! SOURCE
677 : :
678 : 1455 : subroutine time_set_papiopt(opt)
679 : :
680 : : !Arguments ------------------------------------
681 : : integer,intent(in) :: opt
682 : : ! *************************************************************************
683 : :
684 : 1455 : papiopt = opt
685 : :
686 : 1455 : end subroutine time_set_papiopt
687 : : !!***
688 : :
689 : : !----------------------------------------------------------------------
690 : :
691 : : !!****f* m_time/time_get_papiopt
692 : : !! NAME
693 : : !! time_get_papiopt
694 : : !!
695 : : !! FUNCTION
696 : : !! Return the value of papiopt
697 : : !!
698 : : !! SOURCE
699 : :
700 : 0 : function time_get_papiopt()
701 : :
702 : : !Arguments ------------------------------------
703 : : integer :: time_get_papiopt
704 : : ! *************************************************************************
705 : :
706 : 0 : time_get_papiopt = papiopt
707 : :
708 : 0 : end function time_get_papiopt
709 : : !!***
710 : :
711 : : !!****f* m_time/timab
712 : : !! NAME
713 : : !! timab
714 : : !!
715 : : !! FUNCTION
716 : : !! Timing subroutine. Calls machine-dependent "timein" which returns elapsed cpu and wall clock times in sec.
717 : : !! Depending on value of "option" routine will:
718 : : !!
719 : : !! 0: Zero all accumulators
720 : : !! 1 or -1: Start with new incremental time slice for accumulator n using explicit call to timein (or PAPI)
721 : : !! 2 or -2: Stop time slice; add time to accumulator n also increase by one the counter for this accumulator
722 : : !! 3: DEPRECATED Start with new incremental time slice for accumulator n
723 : : !! using stored values for cpu, wall, and PAPI infos ( ! do not use for stop )
724 : : !! Typically used immediately after a call to timab for another counter with option=2. This saves one call to timein.
725 : : !! 4: Report time slice for accumlator n (not full time accumlated)
726 : : !! 5: Option to suppress timing (nn should be 0) or reenable it (nn /=0)
727 : : !! For negative options: same action than positive values, except for -1 and -2,
728 : : !! use stored values for cpu, wall, and PAPI infos ( ! do not use for stop ), instead of calling "timein".
729 : : !! Typically used immediately after a call to timab for another counter with option=2 or 1. This saves one call to timein.
730 : : !!
731 : : !! If, on first entry, subroutine is not being initialized, it will automatically initialize as well as rezero accumulator n.
732 : : !! However, initialization SHOULD be done explicitly by the user so that it can be done near the top of his/her main routine.
733 : : !!
734 : : !! INPUTS
735 : : !! nn=index of accumulator (distinguish what is being timed); NOT used if option=0
736 : : !! option=see comment above
737 : : !!
738 : : !! OUTPUT
739 : : !! on option=4:
740 : : !! tottim(2,nn)=accumulated time for accumulator nn; otherwise tottim is a dummy variable.
741 : : !! option gives the number of times that the accumulator has been incremented
742 : : !!
743 : : !! SOURCE
744 : : !!
745 : :
746 : 859571023 : subroutine timab(nn, option, tottim)
747 : :
748 : : #ifdef HAVE_PAPI
749 : : #include "f90papi.h"
750 : : #endif
751 : :
752 : : !Arguments ------------------------------------
753 : : !scalars
754 : : integer,intent(in) :: nn,option
755 : : !arrays
756 : : real(dp),intent(out) :: tottim(2)
757 : :
758 : : !Local variables-------------------------------
759 : : !scalars
760 : : real(dp),save :: cpu,wall
761 : : character(len=500) :: msg
762 : : #ifdef HAVE_PAPI
763 : : integer(C_INT) :: check
764 : : integer(C_LONG_LONG),save :: flops1
765 : : real(C_FLOAT),save :: real_time,proc_time
766 : : real(C_FLOAT) :: mflops1
767 : : character(len=PAPI_MAX_STR_LEN) :: papi_errstr
768 : : #endif
769 : : ! *************************************************************************
770 : :
771 [ + + ]: 859571023 : if (option==5) timopt=mod(nn,10)
772 : :
773 : : ! If timopt was set to zero by a call with option=5, suppress
774 : : ! all action of this routine (might as well return at this point !)
775 [ + + + + ]: 859571023 : if(timopt/=0 .and. option/=5)then
776 : : ! Check that nn lies in sensible bounds
777 [ - + ]: 66785973 : if (nn<1.or.nn>TIMER_SIZE) then
778 : 0 : write(msg,'(2(a,i0))')' TIMER_SIZE = ',TIMER_SIZE,' but input nn = ',nn
779 : 0 : ABI_BUG(msg)
780 : : end if
781 : :
782 : : #ifdef HAVE_PAPI
783 : : ! for all active options for time if papi analysis has been selected.
784 : : if (option/=3.and.time_get_papiopt()==1) then
785 : : call PAPIf_flops(real_time, proc_time, flops1, mflops1, check)
786 : : if (check /= PAPI_OK) then
787 : : call papif_perror(check,papi_errstr,check)
788 : : write(std_out,*) 'Problem to initialize papi high level inteface'
789 : : write(std_out,*) 'Error code', papi_errstr
790 : : end if
791 : : if (flops1 < 0) then
792 : : ABI_WARNING("Number of floating point instruction Overflow")
793 : : papi_flops(:)=-1
794 : : end if
795 : : end if
796 : : #endif
797 : :
798 : 66787563 : select case (abs(option))
799 : : case (0)
800 : : ! Zero out all accumulators of time and init timers
801 : 1590 : acctim(:,:) = 0.0d0
802 : 1590 : tzero(:,:) = 0.0d0
803 : 1590 : ncount(:) = 0
804 : 1590 : papi_flops(:) = 0
805 : 1590 : papi_acctim(:,:) = 0.
806 : 1590 : papi_accflops(:) = 0.
807 : 1590 : papi_tzero(:,:) = 0.
808 : :
809 : : case (1)
810 : : ! Initialize timab for nn
811 [ + + ]: 33380754 : if(option>0) call timein(cpu,wall)
812 : 33380754 : tzero(1,nn)=cpu
813 : 33380754 : tzero(2,nn)=wall
814 : : #ifdef HAVE_PAPI
815 : : papi_flops(nn) = flops1 ! Initialize megaflops for nn
816 : : papi_tzero(1,nn) = proc_time
817 : : papi_tzero(2,nn) = real_time
818 : : #endif
819 : :
820 : : case (2)
821 : : ! Accumulate time for nn (also keep the values of cpu, wall, proc_time, real_time, flops1)
822 [ + + ]: 33393401 : if(option>0)call timein(cpu,wall)
823 : 33393401 : acctim(1,nn)=acctim(1,nn)+cpu -tzero(1,nn)
824 : 33393401 : acctim(2,nn)=acctim(2,nn)+wall-tzero(2,nn)
825 : 33393401 : ncount(nn)=ncount(nn)+1
826 : : #ifdef HAVE_PAPI
827 : : ! accumulate time and flops for nn Difference between 2 calls to Papif_flops
828 : : papi_acctim(1,nn)=papi_acctim(1,nn)+ proc_time - papi_tzero(1,nn)
829 : : papi_acctim(2,nn)=papi_acctim(2,nn)+ real_time - papi_tzero(2,nn)
830 : : papi_accflops(nn)=papi_accflops(nn)+ flops1- papi_flops(nn)
831 : : #endif
832 : :
833 : : !Should be suppressed, equivalent to -1
834 : : case (3)
835 : : ! Use previously obtained values to initialize timab for nn
836 : : ! Typically used immediately after a call to timab for another counter with option=2 . This saves one call to timein.
837 : 10228 : tzero(1,nn)=cpu
838 : 10228 : tzero(2,nn)=wall
839 : : #ifdef HAVE_PAPI
840 : : papi_flops(nn)=flops1
841 : : papi_tzero(1,nn) = proc_time
842 : : papi_tzero(2,nn) = real_time
843 : : #endif
844 : :
845 : : case (4)
846 : : ! Return elapsed time for nn (do not accumulate)
847 : 0 : call timein(cpu,wall)
848 : 0 : tottim(1)=cpu-tzero(1,nn)
849 : 0 : tottim(2)=wall-tzero(2,nn)
850 : : #ifdef HAVE_PAPI
851 : : ! return elapsed floating point operationfor nn (do not accumulate)
852 : : papi_tottim(1,nn)= proc_time - papi_tzero(1,nn)
853 : : papi_tottim(2,nn)= real_time - papi_tzero(2,nn)
854 : : papi_totflops(nn)= flops1 - papi_flops(nn)
855 : : #endif
856 : :
857 : : case default
858 : 0 : write(msg,'(a,i10,a)')' Input option not valid, =',option,'.'
859 [ + + + + : 66785973 : ABI_BUG(msg)
- - ]
860 : : end select
861 : : end if
862 : :
863 : 859571023 : end subroutine timab
864 : : !!***
865 : :
866 : : end module m_time
|