! ! Parallel Sparse BLAS version 3.5 ! (C) Copyright 2006-2018 ! Salvatore Filippone ! Alfredo Buttari ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions ! are met: ! 1. Redistributions of source code must retain the above copyright ! notice, this list of conditions and the following disclaimer. ! 2. Redistributions in binary form must reproduce the above copyright ! notice, this list of conditions, and the following disclaimer in the ! documentation and/or other materials provided with the distribution. ! 3. The name of the PSBLAS group or the names of its contributors may ! not be used to endorse or promote products derived from this ! software without specific written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ! ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ! TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ! PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PSBLAS GROUP OR ITS CONTRIBUTORS ! BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! POSSIBILITY OF SUCH DAMAGE. ! ! ! ! Purpose: ! Provide a set of timers ! ! module psb_timers_mod use psb_const_mod use psb_realloc_mod use psb_error_mod use psb_penv_mod public psb_init_timers, psb_get_timer_idx, psb_reset_timers,& & psb_tic, psb_toc, psb_print_timers, psb_get_timer private ! Reallocation integer(psb_ipk_), parameter :: ntchunk = 50 integer(psb_ipk_), save :: active_timers = 0 ! Indices integer(psb_ipk_), parameter :: timer_tic_ = 1, timer_toc_ = 2 integer(psb_ipk_), parameter :: timer_x_ = 3, timer_sum_ = 4 integer(psb_ipk_), parameter :: timer_max_ = 5 integer(psb_ipk_), parameter :: timer_avg_ = 6, timer_min_ = 7 integer(psb_ipk_), parameter :: timer_entries_ = 7 ! The data itself type psb_string_item character(len=40) :: data end type psb_string_item integer(psb_ipk_), allocatable :: nsamples(:) real(psb_dpk_), allocatable :: timers(:,:) type(psb_string_item), allocatable :: timers_descr(:) logical :: wanted(timer_entries_) type(psb_string_item) :: entries_descr(timer_entries_) save :: nsamples, timers, timers_descr, wanted, entries_descr interface psb_realloc module procedure psb_string_item_realloc end interface psb_realloc contains subroutine print_timer(me, timer, timer_descr, iout) implicit none integer(psb_ipk_), intent(in) :: me real(psb_dpk_), intent(in) :: timer(timer_entries_) type(psb_string_item), intent(in) :: timer_descr integer(psb_ipk_), optional :: iout character(len=36) :: tmpname integer(psb_ipk_) :: iout_, i if (present(iout)) then iout_ = iout else iout_ = psb_out_unit end if write(tmpname,'(a)') trim(timer_descr%data)//":" write(iout_,'(a36,4(1x,a,f10.2))') tmpname,& & "Sum: ",timer(timer_sum_), & & "Avg: ",timer(timer_avg_), & & "Max: ",timer(timer_max_), & & "Min: ",-timer(timer_min_) end subroutine print_timer subroutine psb_print_timers(ictxt, idx, proc, global, iout) implicit none integer(psb_ipk_), intent(in) :: ictxt integer(psb_ipk_), intent(in), optional :: idx, proc, iout logical, optional :: global ! ! ! integer(psb_ipk_) :: me,np,info,i,j, idxmin_, idxmax_, proc_ real(psb_dpk_) :: gtimers(timer_entries_) real(psb_dpk_), allocatable :: ptimers(:,:) logical :: global_ call psb_info(ictxt,me,np) if (present(global)) then global_ = global else global_ = .true. end if if (present(proc)) then proc_ = proc else proc_ = -1 end if if (present(idx)) then idxmin_ = idx idxmax_ = idx else idxmin_ = 1 idxmax_ = active_timers end if if (global_) then if (allocated(timers)) then allocate(ptimers(timer_entries_,size(timers,2)),stat=info) if (info /= 0) then write(0,*) 'Error while trying to allocate temporary ',info call psb_abort(ictxt) end if ptimers = timers call psb_max(ictxt,ptimers) if (me == psb_root_) then do i=idxmin_, idxmax_ call print_timer(me, ptimers(:,i), timers_descr(i), iout) end do end if end if else if ((proc_ == -1).or.(me==proc_)) then do i=idxmin_, idxmax_ call print_timer(me, ptimers(:,i), timers_descr(i), iout) end do end if end if end subroutine psb_print_timers subroutine psb_reset_timers() active_timers = 0 if (allocated(nsamples)) nsamples = 0 if (allocated(timers)) then timers = dzero timers(timer_min_,:) = -huge(dzero) end if wanted = .true. wanted(timer_tic_) = .false. wanted(timer_toc_) = .false. entries_descr(timer_tic_)%data = "tic" entries_descr(timer_toc_)%data = "toc" entries_descr(timer_x_)%data = "Time" entries_descr(timer_sum_)%data = "Total time" entries_descr(timer_max_)%data = "Max time " entries_descr(timer_avg_)%data = "Average time" entries_descr(timer_min_)%data = "Min time" end subroutine psb_reset_timers subroutine psb_init_timers(ntimers) implicit none integer(psb_ipk_), optional :: ntimers integer(psb_ipk_) :: ntimers_, info if (present(ntimers)) then ntimers_ = ntimers else ntimers_ = ntchunk end if call reallocate_timers(ntimers_,info) if (info == 0) call psb_reset_timers() end subroutine psb_init_timers subroutine reallocate_timers(tsz,info) implicit none integer(psb_ipk_), intent(in) :: tsz integer(psb_ipk_), intent(out) :: info call psb_realloc(timer_entries_,tsz,timers,info) if (info == 0) call psb_realloc(tsz,nsamples,info) if (info == 0) call psb_realloc(tsz,timers_descr,info) end subroutine reallocate_timers function psb_get_timer_idx(string) result(val) implicit none integer(psb_ipk_) :: val character(len=*), intent(in), optional :: string integer(psb_ipk_) :: info val = -1 if (.not.allocated(timers)) call psb_init_timers() if (active_timers >= size(timers,2)) then call reallocate_timers((active_timers+ntchunk),info) if (info /= 0) return nsamples(active_timers+1:) = 0 timers(:,active_timers+1:) = dzero timers(timer_min_,active_timers+1:) = -huge(dzero) end if active_timers = active_timers + 1 if (present(string)) then timers_descr(active_timers)%data = string end if val = active_timers end function psb_get_timer_idx function psb_get_timer(idx) result(val) implicit none real(psb_dpk_) :: val integer(psb_ipk_), intent(in) :: idx ! integer(psb_ipk_) :: info val = dzero if ((1<=idx).and.(idx <= active_timers)) then val = timers(timer_x_,idx) end if end function psb_get_timer subroutine psb_tic(idx) implicit none integer(psb_ipk_), intent(in) :: idx if ((1<=idx).and.(idx <= active_timers)) & & timers(timer_tic_,idx) = psb_wtime() end subroutine psb_tic subroutine psb_toc(idx) implicit none integer(psb_ipk_), intent(in) :: idx if ((1<=idx).and.(idx <= active_timers)) then timers(timer_toc_,idx) = psb_wtime() timers(timer_x_,idx) = & & timers(timer_toc_,idx) - timers(timer_tic_,idx) nsamples(idx) = nsamples(idx) + 1 timers(timer_sum_,idx) = & & timers(timer_sum_,idx) + timers(timer_x_,idx) timers(timer_avg_,idx) = timers(timer_sum_,idx) / nsamples(idx) timers(timer_max_,idx) = & & max(timers(timer_max_,idx), timers(timer_x_,idx)) ! Trick: keep the MAX of negative times, so that ! a MAX over all processes for an entire section ! will give the MIN for the MIN entry. timers(timer_min_,idx) = & & max(timers(timer_min_,idx), (-timers(timer_x_,idx))) end if end subroutine psb_toc Subroutine psb_string_item_realloc(len,rrax,info,lb) use psb_const_mod use psb_error_mod implicit none ! ...Subroutine Arguments integer(psb_ipk_),Intent(in) :: len type(psb_string_item),allocatable, intent(inout) :: rrax(:) integer(psb_ipk_) :: info integer(psb_ipk_), optional, intent(in) :: lb ! ...Local Variables type(psb_string_item),allocatable :: tmp(:) integer(psb_ipk_) :: dim,err_act,err, lb_, lbi,ub_ character(len=20) :: name logical, parameter :: debug=.false. name='psb_string_item_realloc' call psb_erractionsave(err_act) info=psb_success_ if (present(lb)) then lb_ = lb else lb_ = 1 endif if ((len<0)) then err=4025 call psb_errpush(err,name, & & i_err=(/len,izero,izero,izero,izero/),a_err='real(psb_dpk_)') goto 9999 end if ub_ = lb_ + len-1 if (allocated(rrax)) then dim = size(rrax) lbi = lbound(rrax,1) If ((dim /= len).or.(lbi /= lb_)) Then Allocate(tmp(lb_:ub_),stat=info) if (info /= psb_success_) then err=4025 call psb_errpush(err,name, & & i_err=(/len,izero,izero,izero,izero/),a_err='real(psb_dpk_)') goto 9999 end if tmp(lb_:lb_-1+min(len,dim))=rrax(lbi:lbi-1+min(len,dim)) call move_alloc(tmp,rrax) End If else dim = 0 Allocate(rrax(lb_:ub_),stat=info) if (info /= psb_success_) then err=4025 call psb_errpush(err,name, & & i_err=(/len,izero,izero,izero,izero/),a_err='real(psb_dpk_)') goto 9999 end if endif call psb_erractionrestore(err_act) return 9999 continue info = err call psb_error_handler(err_act) return End Subroutine psb_string_item_realloc end module psb_timers_mod