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
|