https://www.cdslab.org/paramonte/fortran/2
Current view: top level - main - pm_bench.F90 (source / functions) Hit Total Coverage
Test: ParaMonte 2.0.0 :: Serial Fortran - Code Coverage Report Lines: 6 6 100.0 %
Date: 2024-04-08 03:18:57 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       2             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       3             : !!!!                                                                                                                            !!!!
       4             : !!!!    ParaMonte: Parallel Monte Carlo and Machine Learning Library.                                                           !!!!
       5             : !!!!                                                                                                                            !!!!
       6             : !!!!    Copyright (C) 2012-present, The Computational Data Science Lab                                                          !!!!
       7             : !!!!                                                                                                                            !!!!
       8             : !!!!    This file is part of the ParaMonte library.                                                                             !!!!
       9             : !!!!                                                                                                                            !!!!
      10             : !!!!    LICENSE                                                                                                                 !!!!
      11             : !!!!                                                                                                                            !!!!
      12             : !!!!       https://github.com/cdslaborg/paramonte/blob/main/LICENSE.md                                                          !!!!
      13             : !!!!                                                                                                                            !!!!
      14             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      15             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      16             : 
      17             : !>  \brief
      18             : !>  This module contains abstract interfaces and types that facilitate benchmarking of different procedures.
      19             : !>
      20             : !>  \details
      21             : !>  The primary useful benchmarking object from this module are<br>
      22             : !>  <ol>
      23             : !>      <li>    [bench_type](@ref pm_bench::bench_type) for benchmarking single or collections of procedures/tasks.<br>
      24             : !>      <li>    [benchMulti_type](@ref pm_bench::benchMulti_type) for facilitating benchmarks of collections of procedures/tasks.<br>
      25             : !>  </ol>
      26             : !>  See the documentations of the respective objects for example usage.<br>
      27             : !>
      28             : !>  \see
      29             : !>  [pm_timer](@ref pm_timer)<br>
      30             : !>
      31             : !>  \test
      32             : !>  [test_pm_bench](@ref test_pm_bench)
      33             : !>
      34             : !>  \finmain{pm_bench}
      35             : !>
      36             : !>  \author
      37             : !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
      38             : 
      39             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      40             : 
      41             : module pm_bench
      42             : 
      43             :     use pm_kind, only: SK, IK, LK, RKD
      44             :     use pm_timer, only: TimerCPU_type
      45             :     use pm_timer, only: TimerDAT_type
      46             : #if MPI_ENABLED
      47             :     use pm_timer, only: timerMPI_type
      48             : #endif
      49             : #if OMP_ENABLED
      50             :     use pm_timer, only: timerOMP_type
      51             : #endif
      52             :     use pm_timer, only: timerSYS_type
      53             :     use pm_timer, only: timer_type
      54             : 
      55             :     implicit none
      56             : 
      57             :     character(*, SK), parameter :: MODULE_NAME = SK_"@pm_bench"
      58             : 
      59             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      60             : 
      61             :     !>  \brief
      62             :     !>  This is the `abstract interface` of the [exec](@ref pm_bench::bench_type) static type-bound procedure pointer
      63             :     !>  component of [bench_type](@ref pm_bench::bench_type) derived type that points to the user-supplied procedure to be timed.
      64             :     !>
      65             :     !>  \finmain{exec_proc}
      66             :     !>
      67             :     !>  \author
      68             :     !>  \AmirShahmoradi, March 23, 2012, 2:21 AM, National Institute for Fusion Studies, The University of Texas at Austin
      69             :     abstract interface
      70             :         subroutine exec_proc()
      71             :         end subroutine exec_proc
      72             :     end interface
      73             : 
      74             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      75             : 
      76             :     !!>  \brief
      77             :     !!>  This is the base class for creating objects that hold the statistics of the timing information of a benchmark.
      78             :     !!>
      79             :     !!>  \remark
      80             :     !!>  This type should generally not be explicitly used outside the [pm_bench](@ref pm_bench).
      81             :     !!>  It merely serves to create the `stat` component of the [timing_type](@ref timing_type) class below.
      82             :     !!>
      83             :     !!>  \see
      84             :     !!>  [timing_type](@ref timing_type)<br>
      85             :     !!>
      86             :     !!>  \test
      87             :     !!>  [test_pm_bench](@ref test_pm_bench)
      88             :     !!>
      89             :     !!>  \finmain{Stat_type}
      90             :     !!>
      91             :     !!>  \author
      92             :     !!>  Amir Shahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
      93             :     !type                :: Stat_type
      94             :     !    real(RKD)       :: min      = -huge(0._RKD) !<  @public The minimum of the timing vector of the benchmark (in seconds).
      95             :     !    real(RKD)       :: max      = -huge(0._RKD) !<  @public The maximum of the timing vector of the benchmark (in seconds).
      96             :     !    real(RKD)       :: std      = -huge(0._RKD) !<  @public The standard deviation of the timing vector of the benchmark (in seconds).
      97             :     !    real(RKD)       :: mean     = -huge(0._RKD) !<  @public The mean of the timing vector of the benchmark (in seconds).
      98             :     !   !real(RKD)       :: median   = -huge(0._RKD) !<  @public The median of the timing vector of the benchmark (in seconds).
      99             :     !   !real(RKD)       :: skewness = -huge(0._RKD) !<  @public The skewness of the timing vector of the benchmark.
     100             :     !   !real(RKD)       :: kurtosis = -huge(0._RKD) !<  @public The kurtosis of the timing vector of the benchmark.
     101             :     !end type Stat_type
     102             : 
     103             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     104             : 
     105             :     !>  \brief
     106             :     !>  This is the base class for creating objects that hold the timing information of a benchmark and the timing statistics.
     107             :     !>
     108             :     !>  \remark
     109             :     !>  This type should generally not be explicitly used outside the [pm_bench](@ref pm_bench).<br>
     110             :     !>  It merely serves to create the `timing` component of the [benchBase_type](@ref benchBase_type) class below.<br>
     111             :     !>
     112             :     !>  \see
     113             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     114             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     115             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     116             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     117             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     118             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     119             :     !>
     120             :     !>  \test
     121             :     !>  [test_pm_bench](@ref test_pm_bench)
     122             :     !>
     123             :     !>  \finmain{timing_type}
     124             :     !>
     125             :     !>  \author
     126             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     127             :     type                                :: timing_type
     128             :        !type(Stat_type)                 :: stat                     !<  @public The object of type [Stat_type](@ref Stat_type) containing the statistics of the `values` component.
     129             :         real(RKD)                       :: overhead = 0._RKD        !<  @public The average timing overhead in units of seconds.
     130             :         real(RKD)                       :: min      = -huge(0._RKD) !<  @public The minimum of the timing vector of the benchmark (in seconds).
     131             :         real(RKD)                       :: max      = -huge(0._RKD) !<  @public The maximum of the timing vector of the benchmark (in seconds).
     132             :         real(RKD)                       :: std      = -huge(0._RKD) !<  @public The standard deviation of the timing vector of the benchmark (in seconds).
     133             :         real(RKD)                       :: mean     = -huge(0._RKD) !<  @public The mean of the timing vector of the benchmark (in seconds).
     134             :        !real(RKD)                       :: median   = -huge(0._RKD) !<  @public The median of the timing vector of the benchmark (in seconds).
     135             :        !real(RKD)                       :: skewness = -huge(0._RKD) !<  @public The skewness of the timing vector of the benchmark.
     136             :        !real(RKD)                       :: kurtosis = -huge(0._RKD) !<  @public The kurtosis of the timing vector of the benchmark.
     137             :         real(RKD)       , allocatable   :: values(:)                !<  @public The vector of timing results in units of seconds, corrected by the average overhead time.
     138             :     end type
     139             : 
     140             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     141             : 
     142             :     !>  \brief
     143             :     !>  This is the base class for creating low-level benchmark objects.
     144             :     !>
     145             :     !>  \details
     146             :     !>  See also the [constructor](@ref pm_bench::constructBench) of this type.<br>
     147             :     !>
     148             :     !>  \interface{benchBase_type}
     149             :     !>  \code{.F90}
     150             :     !>
     151             :     !>      use pm_kind, only: SK, IK, RKD
     152             :     !>      use pm_bench, only: benchBase_type
     153             :     !>      use pm_timer, only: timerCPU_type
     154             :     !>      use pm_timer, only: timerDAT_type
     155             :     !>      use pm_timer, only: timerMPI_type
     156             :     !>      use pm_timer, only: timerOMP_type
     157             :     !>      use pm_timer, only: timerSYS_type
     158             :     !>      type(benchBase_type) :: benchBase
     159             :     !>      character(:, SK) :: name
     160             :     !>      integer(IK) :: miniter
     161             :     !>      real(RKD) :: minsec
     162             :     !>
     163             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerCPU_type())
     164             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerDAT_type())
     165             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerMPI_type())
     166             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerOMP_type())
     167             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerSYS_type())
     168             :     !>
     169             :     !>  \endcode
     170             :     !>
     171             :     !>  \remark
     172             :     !>  See [constructBenchBase](@ref pm_bench::constructBenchBase) for the non-default constructor of this type.<br>
     173             :     !>
     174             :     !>  \note
     175             :     !>  Although it is possible, **this type is not meant to be directly used for benchmarking**.<br>
     176             :     !>  Instead, <b>use the child class [bench_type](@ref pm_bench::bench_type) which greatly simplifies benchmarking</b>.<br>
     177             :     !>
     178             :     !>  \see
     179             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     180             :     !>  [constructBenchBase](@ref pm_bench::constructBenchBase) (constructor of the type)<br>
     181             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     182             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     183             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     184             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     185             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     186             :     !>
     187             :     !>  \example{benchBase_type}
     188             :     !>  \include{lineno} example/pm_bench/benchBase_type/main.F90
     189             :     !>  \compilef
     190             :     !>  \output
     191             :     !>  \include{lineno} example/pm_bench/benchBase_type/main.out.F90
     192             :     !>
     193             :     !>  \test
     194             :     !>  [test_pm_bench](@ref test_pm_bench)
     195             :     !>
     196             :     !>  \finmain{benchBase_type}
     197             :     !>
     198             :     !>  \author
     199             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     200             :     type                                        :: benchBase_type
     201             :         real(RKD)                               :: minsec = 0.05_RKD    !<  @public The minimum time in units of seconds that the benchmark should last. It could take longer, but not less than `minsec`.
     202             :         integer(IK)                             :: miniter = 1_IK       !<  @public The minimum number of timing of the user-specified wrapper procedure. It could run more, but not fewer than `miniter`.
     203             :         type(timing_type)                       :: timing               !<  @public The object of type [timing_type](@ref pm_bench::timing_type) containing the timing information and statistics of the benchmark.
     204             :         character(:, SK)    , allocatable       :: name                 !<  @public The name of the procedure to be timed.
     205             :         class(timer_type)   , allocatable       :: timer                !<  @public The `allocatable` component of `abstract` class [timer_type](@ref pm_timer::timer_type) used for internal timing.<br>
     206             :                                                                         !!          Public access to this component provided is provided solely for the convenience of the user when access to a timer is needed.<br>
     207             :                                                                         !!          Otherwise, it not meant to be directly accessed or manipulated.<br>
     208             :                                                                         !!          The concrete type of this class component is set by the user at runtime depending on their choice of timer.<br>
     209             :     end type
     210             : 
     211             :     !>  \cond excluded
     212             :     interface benchBase_type
     213             :         module procedure :: constructBenchBase
     214             :     end interface
     215             :     !>  \endcond excluded
     216             : 
     217             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     218             : 
     219             :     !>  \brief
     220             :     !>  Construct and return an object of type [benchBase_type](@ref pm_bench::benchBase_type).
     221             :     !>
     222             :     !>  \details
     223             :     !>  This is the constructor of the type [benchBase_type](@ref pm_bench::benchBase_type)
     224             :     !>  for creating objects that facilitate the benchmarking of arbitrary procedures.
     225             :     !>
     226             :     !>  \param[in]  name        :   The input scalar `character` of arbitrary length of default kind \SK,
     227             :     !>                              containing the benchmark name (typically the name of the procedure to be timed).
     228             :     !>  \param[in]  minsec      :   The input scalar of type `real` of kind double precision \RKD representing
     229             :     !>                              the minimum time in units of seconds that the overall benchmark should last.<br>
     230             :     !>                              (**optional**, default = `0.05` seconds)
     231             :     !>  \param[in]  miniter     :   The input scalar of type `integer` of default kind \IK representing
     232             :     !>                              the minimum number of timing the user-specified wrapper procedure repeatedly.<br>
     233             :     !>                              (**optional**, default = `1`)
     234             :     !>  \param[in]  timer       :   The input object of `abstract` class [timer_type](@ref pm_timer::timer_type) representing the benchmark timer.<br>
     235             :     !>                              This object can be one of the available timers in [pm_timer](@ref pm_timer):
     236             :     !>                              <ol>
     237             :     !>                                  <li>    [timerCPU_type](@ref pm_timer::timerCPU_type),
     238             :     !>                                  <li>    [timerDAT_type](@ref pm_timer::timerDAT_type),
     239             :     !>                                  <li>    [timerMPI_type](@ref pm_timer::timerMPI_type),
     240             :     !>                                  <li>    [timerOMP_type](@ref pm_timer::timerOMP_type),
     241             :     !>                                  <li>    [timerSYS_type](@ref pm_timer::timerSYS_type),
     242             :     !>                              </ol>
     243             :     !>                              or any other user-defined subclass of the `abstract` [timer_type](@ref pm_timer::timer_type) class.<br>
     244             :     !>                              (**optional**, default = [timer_type](@ref pm_timer::timer_type))
     245             :     !>
     246             :     !>  \return
     247             :     !>  `benchBase`             :   The output scalar object of type [benchBase_type](@ref pm_bench::benchBase_type).
     248             :     !>
     249             :     !>  \interface{constructBenchBase}
     250             :     !>  \code{.F90}
     251             :     !>
     252             :     !>      use pm_kind, only: SK, IK, RKD
     253             :     !>      use pm_bench, only: benchBase_type
     254             :     !>      use pm_timer, only: timer_type
     255             :     !>      use pm_timer, only: timerCPU_type
     256             :     !>      use pm_timer, only: timerDAT_type
     257             :     !>      use pm_timer, only: timerMPI_type
     258             :     !>      use pm_timer, only: timerOMP_type
     259             :     !>      use pm_timer, only: timerSYS_type
     260             :     !>      type(benchBase_type) :: benchBase
     261             :     !>      character(:, SK) :: name
     262             :     !>      integer(IK) :: miniter
     263             :     !>      real(RKD) :: minsec
     264             :     !>
     265             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timer_type())
     266             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerCPU_type())
     267             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerDAT_type())
     268             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerMPI_type())
     269             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerOMP_type())
     270             :     !>      benchBase = benchBase_type(name, minsec = minsec, miniter = miniter, timer = timerSYS_type())
     271             :     !>
     272             :     !>  \endcode
     273             :     !>
     274             :     !>  \remark
     275             :     !>  See also [benchBase_type](@ref pm_bench::benchBase_type) for possible calling interfaces.<br>
     276             :     !>
     277             :     !>  \remark
     278             :     !>  Note that the timing of the user-specified procedure wrapper is performed **until both conditions related to `minsec` and `miniter` are satisfied**.<br>
     279             :     !>  In other words, the timing is performed for **at least** `minsec` seconds **and at least** `miniter` number of iterations.<br>
     280             :     !>  The default values for these two variables are are set so that the benchmark typically ends within `50 ms`,
     281             :     !>  unless the runtime of the user-specified procedure is longer than `50 ms`.<br>
     282             :     !>
     283             :     !>  \note
     284             :     !>  If the specified benchmark routine is to be called certain number of times,
     285             :     !>  set `minsec = 0.` and `miniter` to desired number of times the routine must be timed.<br>
     286             :     !>
     287             :     !>  \see
     288             :     !>  [benchBase_type](@ref pm_bench::benchBase_type)<br>
     289             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     290             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     291             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     292             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     293             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     294             :     !>
     295             :     !>  \example{constructBenchBase}
     296             :     !>  \include{lineno} example/pm_bench/benchBase_type/main.F90
     297             :     !>  \compilef
     298             :     !>  \output
     299             :     !>  \include{lineno} example/pm_bench/benchBase_type/main.out.F90
     300             :     !>
     301             :     !>  \test
     302             :     !>  [test_pm_bench](@ref test_pm_bench)
     303             :     !>
     304             :     !>  \finmain{constructBenchBase}
     305             :     !>
     306             :     !>  \author
     307             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     308             :     interface constructBenchBase
     309             :     module function constructBenchBase(name, minsec, miniter, timer) result(benchBase)
     310             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     311             :         !DEC$ ATTRIBUTES DLLEXPORT :: constructBenchBase
     312             : #endif
     313             :         use pm_kind, only: SK, IK, RKD
     314             :         use pm_timer, only: timer_type
     315             :         character(*, SK)    , intent(in)                :: name
     316             :         real(RKD)           , intent(in)    , optional  :: minsec
     317             :         integer(IK)         , intent(in)    , optional  :: miniter
     318             :         class(timer_type)   , intent(in)    , optional  :: timer
     319             :         type(benchBase_type)                            :: benchBase
     320             :     end function
     321             :     end interface
     322             : 
     323             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     324             : 
     325             :     !>  \brief
     326             :     !>  This is the class for creating benchmark and performance-profiling objects.
     327             :     !>
     328             :     !>  \details
     329             :     !>  This type has two `public` methods both of which accomplish the same task of timing the user-specified procedure wrapper.<br>
     330             :     !>  However, one ([getTiming](@ref pm_bench::getTiming)) has a `function` interface where the output of the method can be clearly specified,
     331             :     !>  while the other ([setTiming](@ref pm_bench::setTiming)) has a `subroutine` interface where the output of the timing is implicitly assigned
     332             :     !>  to the `timing` component of the parent object of type `bench_type`.<br>
     333             :     !>  The former has an explicit clear calling syntax.<br>
     334             :     !>  The latter has a more concise syntax with potentially faster runtime performance
     335             :     !>  (which is likely irrelevant in almost all practical scenarios).<br>
     336             :     !>
     337             :     !>  See also the [constructor](@ref pm_bench::constructBench) of this type.<br>
     338             :     !>
     339             :     !>  \interface{bench_type}
     340             :     !>  \code{.F90}
     341             :     !>
     342             :     !>      use pm_kind, only: SK, IK, RKD
     343             :     !>      use pm_bench, only: benchBase_type
     344             :     !>      use pm_timer, only: timerCPU_type
     345             :     !>      use pm_timer, only: timerDAT_type
     346             :     !>      use pm_timer, only: timerMPI_type
     347             :     !>      use pm_timer, only: timerOMP_type
     348             :     !>      use pm_timer, only: timerSYS_type
     349             :     !>      type(bench_type) :: bench
     350             :     !>      character(:, SK) :: name
     351             :     !>      integer(IK) :: miniter
     352             :     !>      real(RKD) :: minsec
     353             :     !>
     354             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerCPU_type())
     355             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerDAT_type())
     356             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerMPI_type())
     357             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerOMP_type())
     358             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerSYS_type())
     359             :     !>
     360             :     !>  \endcode
     361             :     !>
     362             :     !>  \see
     363             :     !>  [benchMulti_type](@ref pm_bench::benchMulti_type)<br>
     364             :     !>  [benchBase_type](@ref pm_bench::benchBase_type)<br>
     365             :     !>  [timing_type](@ref pm_bench::timing_type)<br>
     366             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     367             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     368             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     369             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     370             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     371             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     372             :     !>
     373             :     !>  \example{bench_type}
     374             :     !>  \include{lineno} example/pm_bench/bench_type/main.F90
     375             :     !>  \compilef
     376             :     !>  \output
     377             :     !>  \include{lineno} example/pm_bench/bench_type/main.out.F90
     378             :     !>
     379             :     !>  \test
     380             :     !>  [test_pm_bench](@ref test_pm_bench)
     381             :     !>
     382             :     !>  \finmain{bench_type}
     383             :     !>
     384             :     !>  \author
     385             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     386             :     type, extends(benchBase_type)                       :: bench_type
     387             :        !logical(LK)                          , private  :: isdone = .false._LK          !<  \private    The scalar `logical` of default kind \LK that is set to `.true.` once the benchmark is over (used internally to finalize the pointer components of the type).
     388             :         procedure(exec_proc), pointer, nopass, private  :: exec => null()               !<  \private    Procedure Pointer to the user-provided wrapper with explicit interface [exec_proc](@ref pm_bench::exec_proc).
     389             :                                                                                         !!              The wrapper must wrap the user-specified procedure that is to be timed.
     390             :         procedure(exec_proc), pointer, nopass, private  :: overhead => null()           !<  \public     Procedure Pointer to the (user-provided) overhead wrapper with explicit interface [exec_proc](@ref pm_bench::exec_proc).
     391             :                                                                                         !!              The overhead wrapper is used to measure the overhead of the `exec` wrapper component besides
     392             :                                                                                         !!              the cost of calling the wrapped procedure with the `exec` wrapper component.
     393             :     contains
     394             :         final                                           :: finalizeBench                !<  \private    The finalization method of the class.
     395             :         procedure, pass                                 :: getTiming => getTimingMethod !<  \public     The generic method name pointing to `function`   [getTimingMethod](@ref pm_bench::getTiming) be called by the user to initiate the timing of the wrapper for procedure of interest.
     396             :         procedure, pass                                 :: setTiming => setTimingMethod !<  \public     The generic method name pointing to `subroutine` [setTimingMethod](@ref pm_bench::setTiming) be called by the user to initiate the timing of the wrapper for procedure of interest.
     397             :     end type
     398             : 
     399             :     !>  \cond excluded
     400             :     interface bench_type
     401             :         module procedure :: constructBench  !<  This is the [constructor](@ref pm_bench::constructBench) of objects of type [bench_type](@ref pm_bench::bench_type).
     402             :     end interface
     403             :     !>  \endcond excluded
     404             : 
     405             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     406             : 
     407             :     !>  \brief
     408             :     !>  Construct and return an object of type [bench_type](@ref pm_bench::bench_type).
     409             :     !>
     410             :     !>  \details
     411             :     !>  This is the constructor of the type [bench_type](@ref pm_bench::bench_type) for creating objects to
     412             :     !>  perform benchmarking of the user-specified procedures within the user-provided wrapper function.
     413             :     !>
     414             :     !>  \param[in]  name        :   The input scalar `character` of arbitrary length of default kind \SK,
     415             :     !>                              containing the benchmark name (typically the name of the procedure to be timed).
     416             :     !>  \param[in]  exec        :   The input **procedure pointer** with the `abstract interface` [exec_proc](@ref exec_proc)
     417             :     !>                              pointing to the user-defined wrapper procedure that calls the arbitrary procedure to be timed.
     418             :     !>  \param[in]  overhead    :   The input **procedure pointer** with the `abstract interface` [exec_proc](@ref exec_proc)
     419             :     !>                              pointing to a user-defined wrapper procedure that calls everything executed within
     420             :     !>                              wrapper procedure `exec()`, except the call to the procedure that is being timed.<br>
     421             :     !>                              This procedure pointer will be used to measure the overhead due to calling
     422             :     !>                              or executing any non-relevant statements within the wrapper procedure `exec()`.<br>
     423             :     !>                              (**optional**. If missing, then a default empty wrapper procedure will be used to compute the overhead.<br>
     424             :     !>                              Note the default overhead is likely optimized away in production builds of the library,
     425             :     !>                              effectively yielding zero overhead.)
     426             :     !>  \param[in]  minsec      :   The input scalar of type `real` of kind double precision \RKD representing
     427             :     !>                              the minimum time in units of seconds that the overall benchmark should last.<br>
     428             :     !>                              (**optional**. The default is set by the constructor of the parent class [benchBase_type](@ref pm_bench::benchBase_type).)
     429             :     !>  \param[in]  miniter     :   The input scalar of type `integer` of default kind \IK representing
     430             :     !>                              the minimum number of timing the user-specified wrapper procedure repeatedly.<br>
     431             :     !>                              (**optional**. The default is set by the constructor of the parent class [benchBase_type](@ref pm_bench::benchBase_type).)
     432             :     !>  \param[in]  timer       :   The input object of `abstract` class [timer_type](@ref pm_timer::timer_type) representing the benchmark timer.<br>
     433             :     !>                              This object can be one of the available timers in [pm_timer](@ref pm_timer):
     434             :     !>                              <ol>
     435             :     !>                                  <li>    [timerCPU_type](@ref pm_timer::timerCPU_type),
     436             :     !>                                  <li>    [timerDAT_type](@ref pm_timer::timerDAT_type),
     437             :     !>                                  <li>    [timerMPI_type](@ref pm_timer::timerMPI_type),
     438             :     !>                                  <li>    [timerOMP_type](@ref pm_timer::timerOMP_type),
     439             :     !>                                  <li>    [timerSYS_type](@ref pm_timer::timerSYS_type),
     440             :     !>                              </ol>
     441             :     !>                              or any other user-defined subclass of the `abstract` [timer_type](@ref pm_timer::timer_type) class.<br>
     442             :     !>                              (**optional**, default = [timer_type](@ref pm_timer::timer_type))
     443             :     !>
     444             :     !>  \return
     445             :     !>  `bench`                 :   The output scalar object of type [bench_type](@ref pm_bench::bench_type).
     446             :     !>
     447             :     !>  \interface{constructBench}
     448             :     !>  \code{.F90}
     449             :     !>
     450             :     !>      use pm_kind, only: SK, IK, RKD
     451             :     !>      use pm_bench, only: benchBase_type
     452             :     !>      use pm_timer, only: timerCPU_type
     453             :     !>      use pm_timer, only: timerDAT_type
     454             :     !>      use pm_timer, only: timerMPI_type
     455             :     !>      use pm_timer, only: timerOMP_type
     456             :     !>      use pm_timer, only: timerSYS_type
     457             :     !>      use pm_timer, only: timer_type
     458             :     !>      type(bench_type) :: bench
     459             :     !>      character(:, SK) :: name
     460             :     !>      integer(IK) :: miniter
     461             :     !>      real(RKD) :: minsec
     462             :     !>
     463             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timer_type())
     464             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerCPU_type())
     465             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerDAT_type())
     466             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerMPI_type())
     467             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerOMP_type())
     468             :     !>      benchBase = bench_type(name, exec, overhead = overhead, minsec = minsec, miniter = miniter, timer = timerSYS_type())
     469             :     !>
     470             :     !>  \endcode
     471             :     !>
     472             :     !>  \note
     473             :     !>  If the specified benchmark routine is to be called certain number of times,
     474             :     !>  set `minsec = 0.` and `miniter` to desired number of times the routine must be timed.<br>
     475             :     !>
     476             :     !>  \see
     477             :     !>  [benchBase_type](@ref benchBase_type)<br>
     478             :     !>  [benchMulti_type](@ref pm_bench::benchMulti_type)<br>
     479             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     480             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     481             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     482             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     483             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     484             :     !>
     485             :     !>  \example{constructBench}
     486             :     !>  \include{lineno} example/pm_bench/bench_type/main.F90
     487             :     !>  \compilef
     488             :     !>  \output
     489             :     !>  \include{lineno} example/pm_bench/bench_type/main.out.F90
     490             :     !>
     491             :     !>  \test
     492             :     !>  [test_pm_bench](@ref test_pm_bench)
     493             :     !>
     494             :     !>  \finmain{constructBench}
     495             :     !>
     496             :     !>  \author
     497             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     498             :     interface constructBench
     499             :     module function constructBench(name, exec, overhead, minsec, miniter, timer) result(bench)
     500             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     501             :         !DEC$ ATTRIBUTES DLLEXPORT :: constructBench
     502             : #endif
     503             :         use pm_timer, only: timer_type
     504             :         character(*, SK)    , intent(in)            :: name
     505             :         procedure(exec_proc)                        :: exec
     506             :         procedure(exec_proc)            , optional  :: overhead
     507             :         real(RKD)           , intent(in), optional  :: minsec
     508             :         integer(IK)         , intent(in), optional  :: miniter
     509             :         class(timer_type)   , intent(in), optional  :: timer
     510             :         type(bench_type)                            :: bench
     511             :     end function
     512             :     end interface
     513             : 
     514             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     515             : 
     516             :     !>  \brief
     517             :     !>  Generate and return an object of type [timing_type](@ref timing_type) containing the benchmark timing information and statistics.
     518             :     !>
     519             :     !>  \details
     520             :     !>  This procedure is a method of the class [bench_type](@ref pm_bench::bench_type).
     521             :     !>
     522             :     !>  \param[inout]   self    :   The parent object of class [bench_type](@ref pm_bench::bench_type) (passed implicitly to the method).<br>
     523             :     !>  \param[in]      minsec  :   The input scalar `real` of kind double precision \RKD
     524             :     !>                              representing the minimum time in seconds to spend on timing repeatedly.<br>
     525             :     !>                              (**optional**. The default is set by the constructor of the parent class [benchBase_type](@ref pm_bench::benchBase_type).)
     526             :     !>  \param[in]      miniter :   The input scalar `integer` of default kind \IK representing
     527             :     !>                              the minimum number of iterations (repetitions) of the timing to perform.<br>
     528             :     !>                              (**optional**. The default is set by the constructor of the parent class [benchBase_type](@ref pm_bench::benchBase_type).)
     529             :     !>
     530             :     !>  \return
     531             :     !>  `timing`                :   The output object of class [timing_type](@ref timing_type) containing the resulting timing vector and statistics.<br>
     532             :     !>                              For convenience, you can assign this output to the `timing` component of the same [bench_type](@ref pm_bench::bench_type)
     533             :     !>                              object to which this [getTiming](@ref pm_bench::getTiming) method belongs.<br>
     534             :     !>                              See [bench_type](@ref pm_bench::bench_type) for example usage.<br>
     535             :     !>
     536             :     !>  \interface{getTiming}
     537             :     !>  \code{.F90}
     538             :     !>
     539             :     !>      use pm_kind, only: RKD
     540             :     !>      type(bench_type) :: bench
     541             :     !>      real(RKD) :: minsec
     542             :     !>
     543             :     !>      bench = bench_type(name, exec, overhead = overhead, minsec = minsec, timer = timer)
     544             :     !>      bench%timing = bench%getTiming(minsec = minsec, miniter = miniter)
     545             :     !>
     546             :     !>  \endcode
     547             :     !>
     548             :     !>  \remark
     549             :     !>  This `function` method of type [bench_type](@ref pm_bench::bench_type) has the same functionality as the `subroutine`
     550             :     !>  interface [setTiming](@ref pm_bench::setTiming) with the only difference that the output is explicit.
     551             :     !>
     552             :     !>  \note
     553             :     !>  If the specified benchmark routine is to be called certain number of times,
     554             :     !>  set `minsec = 0.` and `miniter` to desired number of times the routine must be timed.<br>
     555             :     !>
     556             :     !>  \see
     557             :     !>  [setTiming](@ref pm_bench::setTiming)<br>
     558             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     559             :     !>
     560             :     !>  \remark
     561             :     !>  See [bench_type](@ref pm_bench::bench_type) for example usage.
     562             :     !>
     563             :     !>  \todo
     564             :     !>  \phigh
     565             :     !>  The computation of the median, skewness, and kurtosis of the timing vector in the `stat` component must be implemented.
     566             :     !>
     567             :     !>  \test
     568             :     !>  [test_pm_bench](@ref test_pm_bench)
     569             :     !>
     570             :     !>  \finmain{getTiming}
     571             :     !>
     572             :     !>  \author
     573             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     574             :     interface getTiming
     575             :     module function getTimingMethod(self, minsec, miniter) result(timing)
     576             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     577             :         !DEC$ ATTRIBUTES DLLEXPORT :: getTimingMethod
     578             : #endif
     579             :         use pm_kind, only: IK, RKD
     580             :         class(bench_type)   , intent(inout)             :: self
     581             :         integer(IK)         , intent(in)    , optional  :: miniter
     582             :         real(RKD)           , intent(in)    , optional  :: minsec
     583             :         type(timing_type)                               :: timing
     584             :     end function
     585             :     end interface
     586             : 
     587             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     588             : 
     589             :     !>  \brief
     590             :     !>  Time the user-specified procedure wrapper in the parent object of type [bench_type](@ref pm_bench::bench_type)
     591             :     !>  and store the output benchmark timing information and statistics implicitly in the `timing` component of
     592             :     !>  the input/output [bench_type](@ref pm_bench::bench_type) object.<br>
     593             :     !>
     594             :     !>  \details
     595             :     !>  This procedure is a method of the class [bench_type](@ref pm_bench::bench_type).<br>
     596             :     !>
     597             :     !>  \details
     598             :     !>
     599             :     !>  \param[inout]   self    :   The parent object of class [bench_type](@ref pm_bench::bench_type) (passed implicitly to the method).<br>
     600             :     !>  \param[in]      miniter :   The input scalar `integer` of default kind \IK representing the minimum number of iterations (repetitions) of the timing to perform.<br>
     601             :     !>                              (**optional**. The default is set by the constructor of the parent class [benchBase_type](@ref pm_bench::benchBase_type).)
     602             :     !>  \param[in]      minsec  :   The input scalar `real` of kind double precision \RKD representing the minimum time in seconds to spend on timing repeatedly.<br>
     603             :     !>                              (**optional**. The default is set by the constructor of the parent class [benchBase_type](@ref pm_bench::benchBase_type).)
     604             :     !>
     605             :     !>  \interface{setTiming}
     606             :     !>  \code{.F90}
     607             :     !>
     608             :     !>      use pm_kind, only: RKD
     609             :     !>      type(bench_type) :: bench
     610             :     !>      real(RKD) :: minsec
     611             :     !>
     612             :     !>      bench = bench_type(name, exec, overhead = overhead, minsec = minsec, timer = timer)
     613             :     !>      call bench%setTiming(minsec = minsec, miniter = miniter)
     614             :     !>
     615             :     !>  \endcode
     616             :     !>
     617             :     !>  \remark
     618             :     !>  This `subroutine` method of type [bench_type](@ref pm_bench::bench_type) has the same functionality as the `function` interface
     619             :     !>  [getTiming](@ref pm_bench::getTiming) with the only difference that the result output is implicit and potentially slightly faster.
     620             :     !>
     621             :     !>  \note
     622             :     !>  If the specified benchmark routine is to be called certain number of times,
     623             :     !>  set `minsec = 0.` and `miniter` to desired number of times the routine must be timed.<br>
     624             :     !>
     625             :     !>  \see
     626             :     !>  [getTiming](@ref pm_bench::getTiming)<br>
     627             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     628             :     !>
     629             :     !>  \remark
     630             :     !>  See [bench_type](@ref pm_bench::bench_type) for example usage.
     631             :     !>
     632             :     !>  \todo
     633             :     !>  \phigh
     634             :     !>  The computation of the median, skewness, and kurtosis of the timing vector in the `stat` component must be implemented.<br>
     635             :     !>
     636             :     !>  \test
     637             :     !>  [test_pm_bench](@ref test_pm_bench)
     638             :     !>
     639             :     !>  \finmain{setTiming}
     640             :     !>
     641             :     !>  \author
     642             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     643             :     interface setTiming
     644             :     module subroutine setTimingMethod(self, minsec, miniter)
     645             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     646             :         !DEC$ ATTRIBUTES DLLEXPORT :: setTimingMethod
     647             : #endif
     648             :         use pm_kind, only: IK, RKD
     649             :         class(bench_type)   , intent(inout)             :: self
     650             :         integer(IK)         , intent(in)    , optional  :: miniter
     651             :         real(RKD)           , intent(in)    , optional  :: minsec
     652             :         !RUN_TIMING(self%timing)
     653             :     end subroutine
     654             :     end interface
     655             : 
     656             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     657             : 
     658             :     !!>  \brief
     659             :     !!>  This is the base class for creating objects that hold the timing information of multiple benchmark objects and the timing statistics.
     660             :     !!>
     661             :     !!>  \remark
     662             :     !!>  This type should generally not be explicitly used outside the [pm_bench](@ref pm_bench).<br>
     663             :     !!>  It merely serves to create the `timing` component of the [benchMulti_type](@ref benchMulti_type) class below.<br>
     664             :     !!>
     665             :     !!>  \see
     666             :     !!>  [benchMulti_type](@ref pm_bench::benchMulti_type)<br>
     667             :     !!>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     668             :     !!>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     669             :     !!>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     670             :     !!>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     671             :     !!>  [timer_type](@ref pm_timer::timer_type)<br>
     672             :     !!>
     673             :     !!>  \test
     674             :     !!>  [test_pm_bench](@ref test_pm_bench)
     675             :     !!>
     676             :     !!>  \finmain{timing_type}
     677             :     !!>
     678             :     !!>  \author
     679             :     !!>  Amir Shahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     680             :     !type                                :: timing_type
     681             :     !    real(RKD)                       :: overhead = 0._RKD        !<  \public The average timing overhead in units of seconds.
     682             :     !    real(RKD)                       :: min      = -huge(0._RKD) !<  \public The minimum of the timing vector of the benchmark (in seconds).
     683             :     !    real(RKD)                       :: max      = -huge(0._RKD) !<  \public The maximum of the timing vector of the benchmark (in seconds).
     684             :     !    real(RKD)                       :: std      = -huge(0._RKD) !<  \public The standard deviation of the timing vector of the benchmark (in seconds).
     685             :     !    real(RKD)                       :: mean     = -huge(0._RKD) !<  \public The mean of the timing vector of the benchmark (in seconds).
     686             :     !   !real(RKD)                       :: median   = -huge(0._RKD) !<  \public The median of the timing vector of the benchmark (in seconds).
     687             :     !   !real(RKD)                       :: skewness = -huge(0._RKD) !<  \public The skewness of the timing vector of the benchmark.
     688             :     !   !real(RKD)                       :: kurtosis = -huge(0._RKD) !<  \public The kurtosis of the timing vector of the benchmark.
     689             :     !    type(container) , allocatable   :: case(:)                  !<  \public The matrix of timing results in units of seconds, corrected by the average overhead time.
     690             :     !end type
     691             : 
     692             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     693             : 
     694             :     !>  \brief
     695             :     !>  This is the class for creating object to perform multiple benchmarks and performance-profiling.
     696             :     !>
     697             :     !>  \details
     698             :     !>  This type facilitates comparison of performances of **multiple** user-specified procedure wrappers
     699             :     !>  by reducing the amount of code to be written and automating and randomizing the timing schemes.<br>
     700             :     !>  See also [constructBenchMulti](@ref pm_bench::constructBenchMulti), the type constructor.<br>
     701             :     !>
     702             :     !>  \interface{benchMulti_type}
     703             :     !>  \code{.F90}
     704             :     !>
     705             :     !>      type(benchMulti_type) :: self(:)
     706             :     !>      type(bench_type), allocatable :: case(:)
     707             :     !>
     708             :     !>      self = benchMulti_type(case(:))
     709             :     !>
     710             :     !>  \endcode
     711             :     !>
     712             :     !>  \see
     713             :     !>  [constructBenchMulti](@ref pm_bench::constructBenchMulti)<br>
     714             :     !>  [showsum](@ref pm_bench::showsum)<br>
     715             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     716             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     717             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     718             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     719             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     720             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     721             :     !>
     722             :     !>  \example{benchMulti_type}
     723             :     !>  \include{lineno} example/pm_bench/benchMulti_type/main.F90
     724             :     !>  \compilef
     725             :     !>  \output
     726             :     !>  \include{lineno} example/pm_bench/benchMulti_type/main.out.F90
     727             :     !>
     728             :     !>  \test
     729             :     !>  [test_pm_bench](@ref test_pm_bench)
     730             :     !>
     731             :     !>  \finmain{benchMulti_type}
     732             :     !>
     733             :     !>  \author
     734             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     735             :     type                                    :: benchMulti_type
     736             :         integer(IK)                         :: ncase                        !<  The scalar `integer` of default kind \IK
     737             :                                                                             !!  containing the number of user-specified benchmark cases.
     738             :         character(:, SK)    , allocatable   :: name                         !<  The `allocatable` scalar `character` of default kind \SK
     739             :                                                                             !!  containing the names of benchmark cases separated with `" vs."`.
     740             :         type(bench_type)    , allocatable   :: case(:)                      !<  The vector component object of type [bench_type](@ref pm_bench::bench_type)
     741             :                                                                             !!  of size `ncase * repeat` containing the Benchmark cases.<br>
     742             :        !type(timing_type)                   :: timing                       !<  The object of type [timing_type](@ref pm_bench::timing_type) containing
     743             :        !                                                                    !!  the timing information and statistics of the benchmark.
     744             :     contains
     745             :         procedure, pass                     :: showsum => showsum_          !<  The generic object method name that points to [showsum](@ref pm_bench::showsum).
     746             :     end type
     747             : 
     748             :     interface benchMulti_type
     749             :         module procedure :: constructBenchMulti
     750             :     end interface
     751             : 
     752             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     753             : 
     754             :     !>  \brief
     755             :     !>  Construct, perform multiple benchmarking, and return the multiple benchmarking
     756             :     !>  results as an object of type [benchMulti_type](@ref pm_bench::benchMulti_type).
     757             :     !>
     758             :     !>  \details
     759             :     !>  This is the constructor of the type [benchMulti_type](@ref benchMulti_type) for creating objects that automate,
     760             :     !>  benchmark, and compare the performances of **multiple** user-specified procedure wrappers.<br>
     761             :     !>
     762             :     !>  \param[inout]   case    :   The input `contiguous` vector of arbitrary size of type [bench_type](@ref pm_bench::bench_type)
     763             :     !>                              containing the multiple benchmark object instances corresponding to each user-specified procedure wrapper.<br>
     764             :     !>  \param[in]      repeat  :   The input scalar `integer` of default kind \IK, representing the number of times each benchmark must be done to obtain reliable results.<br>
     765             :     !>                              Setting `repeat` to a large number can significantly increase the overall runtime of the benchmark list, since each one will be repeated `repeat` times.<br>
     766             :     !>                              However, it can also lead to potentially less-biased and most accurate benchmark results and comparison.<br>
     767             :     !>                              (**optional**, default = `2_IK`, i.e., each benchmark will be repeated twice and the results will be averaged for each benchmark instance.)
     768             :     !>  \param[in]      sorted  :   The input scalar `logical` of default kind \LK.<br>
     769             :     !>                              If `.true.`, the input benchmark instances `case` will be called and timed in the same order as given.<br>
     770             :     !>                              Otherwise, the order of the calls to the benchmarks instances are randomized.<br>
     771             :     !>                              A `.false.` input value aids the removal of potential biases due to the orderly calling of benchmark instances.<br>
     772             :     !>                              (**optional**, default = `.false._LK`)
     773             :     !>
     774             :     !>  \return
     775             :     !>  `self`                  :   The output scalar object of type [benchMulti_type](@ref pm_bench::benchMulti_type).
     776             :     !>
     777             :     !>  \interface{constructBenchMulti}
     778             :     !>  \code{.F90}
     779             :     !>
     780             :     !>      type(benchMulti_type) :: self(:)
     781             :     !>      type(bench_type), allocatable :: case(:)
     782             :     !>
     783             :     !>      self = benchMulti_type(case(:), sorted = sorted, repeat = repeat)
     784             :     !>
     785             :     !>  \endcode
     786             :     !>
     787             :     !>  \see
     788             :     !>  [showsum](@ref pm_bench::showsum)<br>
     789             :     !>  [benchMulti_type](@ref pm_bench::benchMulti_type)<br>
     790             :     !>  [bench_type](@ref pm_bench::bench_type)<br>
     791             :     !>  [timer_type](@ref pm_timer::timer_type)<br>
     792             :     !>  [timerDAT_type](@ref pm_timer::timerDAT_type)<br>
     793             :     !>  [timerMPI_type](@ref pm_timer::timerMPI_type)<br>
     794             :     !>  [timerOMP_type](@ref pm_timer::timerOMP_type)<br>
     795             :     !>  [timerSYS_type](@ref pm_timer::timerSYS_type)<br>
     796             :     !>
     797             :     !>  \example{constructBenchMulti}
     798             :     !>  \include{lineno} example/pm_bench/benchMulti_type/main.F90
     799             :     !>  \compilef
     800             :     !>  \output
     801             :     !>  \include{lineno} example/pm_bench/benchMulti_type/main.out.F90
     802             :     !>
     803             :     !>  \test
     804             :     !>  [test_pm_bench](@ref test_pm_bench)
     805             :     !>
     806             :     !>  \todo
     807             :     !>  \pvlow
     808             :     !>  The current construction of the `name` component of the output object relies on repeated allocation of `name`.<br>
     809             :     !>  This can be improved by removing the redundant allocation in future, although any performance benefits are questionable.<br>
     810             :     !>
     811             :     !>  \finmain{constructBenchMulti}
     812             :     !>
     813             :     !>  \author
     814             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     815             :     interface constructBenchMulti
     816             :     module function constructBenchMulti(case, sorted, repeat) result(self)
     817             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     818             :         !DEC$ ATTRIBUTES DLLEXPORT :: constructBenchMulti
     819             : #endif
     820             :         use pm_kind, only: IK, LK
     821             :         type(benchMulti_type)                           :: self
     822             :         type(bench_type)    , intent(in), contiguous    :: case(:)
     823             :         logical(LK)         , intent(in), optional      :: sorted
     824             :         integer(IK)         , intent(in), optional      :: repeat
     825             :     end function
     826             :     end interface
     827             : 
     828             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     829             : 
     830             :     !>  \brief
     831             :     !>  Time the user-specified procedure wrappers in the `case` vector
     832             :     !>  component of the parent object of type [benchMulti_type](@ref pm_bench::benchMulti_type)
     833             :     !>  and store the output benchmark timing information and statistics implicitly in the `timing` component of the object.
     834             :     !>
     835             :     !>  \details
     836             :     !>  This procedure is a method of the class [benchMulti_type](@ref pm_bench::benchMulti_type).
     837             :     !>
     838             :     !>  \param[inout]   self        :   The input/output object of class [benchMulti_type](@ref pm_bench::benchMulti_type) (passed implicitly to the method).
     839             :     !>  \param[out]     unit        :   The input scalar of type `integer` of default kind \IK containing the output unit
     840             :     !>                                  (e.g., output_unit, or an external file unit) where the results should be displayed.<br>
     841             :     !>                                  (**optional**, default = `output_unit` taken from `iso_fortran_env` Fortran intrinsic module.)
     842             :     !>  \param[in]      tabular     :   The input scalar `logical` of default kind \LK. If `.true.`, then the results
     843             :     !>                                  will be output to the supplied file `unit` in simple ASCII tabular format.<br>
     844             :     !>                                  The non-tabular format is specially desirable for scenarios where the output
     845             :     !>                                  should be postprocessed by other software or in other programming languages.<br>
     846             :     !>                                  (**optional**, default = `.true.` if the input `unit` corresponds to `output_unit`
     847             :     !>                                  from `iso_fortran_env` intrinsic Fortran module and `.false.` otherwise.)
     848             :     !>
     849             :     !>  \interface{showsum}
     850             :     !>  \code{.F90}
     851             :     !>
     852             :     !>      type(benchMulti_type) :: self
     853             :     !>
     854             :     !>      call self%showsum(unit = unit, tabular = tabular)
     855             :     !>
     856             :     !>  \endcode
     857             :     !>
     858             :     !>  \impure
     859             :     !>
     860             :     !>  \see
     861             :     !>  [benchMulti_type](@ref pm_bench::benchMulti_type)<br>
     862             :     !>
     863             :     !>  \remark
     864             :     !>  See [benchMulti_type](@ref pm_bench::benchMulti_type) for example usage.
     865             :     !>
     866             :     !>  \test
     867             :     !>  [test_pm_bench](@ref test_pm_bench)
     868             :     !>
     869             :     !>  \finmain{showsum}
     870             :     !>
     871             :     !>  \author
     872             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     873             :     interface showsum
     874             :     module subroutine showsum_(self, unit, tabular)
     875             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     876             :         !DEC$ ATTRIBUTES DLLEXPORT :: showsum_
     877             : #endif
     878             :         class(benchMulti_type)  , intent(in)            :: self
     879             :         integer(IK)             , intent(in), optional  :: unit
     880             :         logical(LK)             , intent(in), optional  :: tabular
     881             :     end subroutine
     882             :     end interface
     883             : 
     884             : contains
     885             : 
     886             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     887             : 
     888           1 :     subroutine finalizeBench(self)
     889             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     890             :         !DEC$ ATTRIBUTES DLLEXPORT :: finalizeBench
     891             : #endif
     892             :         type(bench_type), intent(inout) :: self
     893             :         !if (self%isdone) then
     894           1 :         nullify(self%overhead)
     895           1 :         nullify(self%exec)
     896             :         !end if
     897           1 :     end subroutine
     898             : 
     899             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     900             : 
     901             :     !>  \brief
     902             :     !>  Take nothing, [do nothing](https://www.youtube.com/watch?v=w0jcXD1m0W4), and return nothing.<br>
     903             :     !>
     904             :     !>  \details
     905             :     !>  This generic interface is simply an empty wrapper to a serve as proxy for subroutine call overhead in benchmarks.<br>
     906             :     !>
     907             :     !>  \impure
     908             :     !>
     909             :     !>  \see
     910             :     !>  [benchMulti_type](@ref pm_bench::benchMulti_type)<br>
     911             :     !>
     912             :     !>  \remark
     913             :     !>  See [benchMulti_type](@ref pm_bench::benchMulti_type) for example usage.
     914             :     !>
     915             :     !>  \test
     916             :     !>  [test_pm_bench](@ref test_pm_bench)
     917             :     !>
     918             :     !>  \finmain{doNothing}
     919             :     !>
     920             :     !>  \author
     921             :     !>  \AmirShahmoradi, Wednesday 4:13 AM, August 13, 2016, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
     922      268566 :     impure subroutine doNothing()
     923             : #if __INTEL_COMPILER && DLL_ENABLED && (_WIN32 || _WIN64)
     924             :         !DEC$ ATTRIBUTES DLLEXPORT :: doNothing
     925             : #endif
     926      268566 :     end subroutine
     927             : 
     928             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     929             : 
     930             : end module pm_bench ! LCOV_EXCL_LINE

ParaMonte: Parallel Monte Carlo and Machine Learning Library 
The Computational Data Science Lab
© Copyright 2012 - 2024