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 7551 : 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 7551 : call date_and_time(strdat,strtime,strzone,values)
121 :
122 7551 : year=values(1)
123 7551 : mm=values(2)
124 7551 : dd=values(3)
125 :
126 : !Get day of the week
127 7551 : if (mm > 2) then
128 7551 : jy=year
129 7551 : jm=mm+1
130 : else
131 0 : jy=year-1
132 0 : jm=mm+13
133 : end if
134 :
135 7551 : jdn=int(365.25d0*jy)+int(30.6001d0*jm)+dd+1720995
136 7551 : ja=int(0.01d0*jy)
137 7551 : jdn=jdn+2-ja+int(quarter*ja)
138 7551 : 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 7551 : day_names(day),month_names(mm),dd,values(5),":",values(6),":",values(7),year
143 :
144 7551 : 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 407462 : 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 407462 : days = time_s / 86400
176 407462 : hours = MOD(time_s,86400._dp) / 3600
177 407462 : minutes = MOD(time_s,3600._dp) / 60
178 407462 : seconds = MOD(time_s,60._dp)
179 :
180 407462 : if (days > 0) then
181 0 : write(str,'(i0,3(a,i0.2),a)')days,"-",hours,":",minutes,":",seconds, " [days]"
182 407462 : else if (hours > 0) then
183 5 : write(str,'(i0.2,2(a,i0.2),a)')hours,":",minutes,":",seconds, " [hours]"
184 407457 : else if (minutes > 0) then
185 57 : write(str,'(i0.2,a,i0.2,a)')minutes,":",seconds, " [minutes]"
186 : else
187 407400 : write(str,'(f5.2,a)')time_s," [s]"
188 : end if
189 :
190 407462 : 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 70880998 : 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 1521373 : call cpu_time(cpu_sp)
323 70880998 : 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 72587058 : 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 1706060 : wall = MPI_WTIME()
422 : #endif
423 :
424 1706060 : 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 1521373 : 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 1521373 : if (present(msg)) call wrtout(std_out, msg)
484 :
485 : select case (start_or_stop)
486 : case ("start")
487 854541 : 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 854541 : 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 666832 : cpu = abi_cpu_time() - cpu; wall = abi_wtime() - wall; gflops = -one
500 : end if
501 666832 : 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 1521373 : ABI_ERROR("Wrong option for start_or_stop: "//trim(start_or_stop))
510 : end select
511 :
512 1521373 : 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 344870 : 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 172435 : if (present(comm)) then
554 245 : call cwtime(cpu, wall, gflops, "stop", comm=comm)
555 245 : avg_type = "(MPI average) <<< TIME"
556 : else
557 172190 : call cwtime(cpu, wall, gflops, "stop")
558 172190 : avg_type = "<<< TIME"
559 : end if
560 172435 : if (present(pre_str)) call wrtout(std_out, pre_str)
561 :
562 172435 : 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 172435 : if (present(end_str)) call wrtout(std_out, end_str)
566 172435 : if (present(out_wall)) out_wall = wall
567 :
568 172435 : 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 172435 : 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 69359625 : subroutine timein(cpu,wall)
601 :
602 : !Arguments ------------------------------------
603 : real(dp),intent(out) :: cpu,wall
604 : ! *************************************************************************
605 :
606 : ! CPU time
607 69359625 : cpu = abi_cpu_time()
608 : ! Wall time
609 69359625 : wall = abi_wtime()
610 :
611 69359625 : 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 277834 : 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 277834 : 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 277834 : tottim(1)=acctim(1,nn)
656 277834 : tottim(2)=acctim(2,nn)
657 :
658 : !return accumulated number flops for nn
659 277834 : totflops = papi_accflops(nn)
660 :
661 : !return accumulated time for nn evaluated by papi
662 277834 : totftimes(1) = papi_acctim(1,nn)
663 277834 : totftimes(2) = papi_acctim(2,nn)
664 277834 : return_ncount=ncount(nn)
665 :
666 277834 : 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 1442 : subroutine time_set_papiopt(opt)
679 :
680 : !Arguments ------------------------------------
681 : integer,intent(in) :: opt
682 : ! *************************************************************************
683 :
684 1442 : papiopt = opt
685 :
686 1442 : 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 856630812 : 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 856630812 : 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 856630812 : if(timopt/=0 .and. option/=5)then
776 : ! Check that nn lies in sensible bounds
777 69160925 : 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 69162500 : select case (abs(option))
799 : case (0)
800 : ! Zero out all accumulators of time and init timers
801 1575 : acctim(:,:) = 0.0d0
802 1575 : tzero(:,:) = 0.0d0
803 1575 : ncount(:) = 0
804 1575 : papi_flops(:) = 0
805 1575 : papi_acctim(:,:) = 0.
806 1575 : papi_accflops(:) = 0.
807 1575 : papi_tzero(:,:) = 0.
808 :
809 : case (1)
810 : ! Initialize timab for nn
811 34568244 : if(option>0) call timein(cpu,wall)
812 34568244 : tzero(1,nn)=cpu
813 34568244 : 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 34580891 : if(option>0)call timein(cpu,wall)
823 34580891 : acctim(1,nn)=acctim(1,nn)+cpu -tzero(1,nn)
824 34580891 : acctim(2,nn)=acctim(2,nn)+wall-tzero(2,nn)
825 34580891 : 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 10215 : tzero(1,nn)=cpu
838 10215 : 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 69160925 : ABI_BUG(msg)
860 : end select
861 : end if
862 :
863 856630812 : end subroutine timab
864 : !!***
865 :
866 : end module m_time
|