-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathBaseProfiler.F90
More file actions
501 lines (384 loc) · 13.5 KB
/
BaseProfiler.F90
File metadata and controls
501 lines (384 loc) · 13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
#include "MAPL_ErrLog.h"
#include "unused_dummy.H"
module mapl_BaseProfiler
use mapl_AdvancedMeter
use mapl_AbstractMeter
use mapl_AbstractMeterNode
use mapl_MeterNode
use mapl_MeterNodePtr
use mapl_MeterNodeStack
use mapl_ErrorHandlingMod
use mapl_KeywordEnforcerMod
implicit none
private
public :: BaseProfiler
public :: BaseProfilerIterator
public :: INCORRECTLY_NESTED_METERS
enum, bind(c)
enumerator :: INCORRECTLY_NESTED_METERS=1
end enum
type, abstract :: BaseProfiler
private
type(MeterNode) :: root_node
type(MeterNodeStack) :: stack
integer :: status
integer :: comm_world
contains
procedure :: start_name
procedure :: stop_name
procedure :: start_node
procedure :: stop_node
procedure :: start_self
procedure :: stop_self
generic :: start => start_name
generic :: start => start_node
generic :: start => start_self
generic :: stop => stop_name
generic :: stop => stop_node
generic :: stop => stop_self
generic :: zeit_ci => start_name
generic :: zeit_co => stop_name
procedure :: get_num_meters
procedure :: finalize
! Override make_meter() to measure other things.
procedure(i_make_meter), deferred :: make_meter
procedure :: set_node
procedure :: get_root_node
procedure :: get_status
procedure :: copy_profiler
procedure :: reset
procedure :: accumulate
procedure :: begin => begin_profiler
procedure :: end => end_profiler
procedure :: get_depth
procedure :: set_comm_world
end type BaseProfiler
type :: BaseProfilerIterator
private
class (AbstractMeterNodeIterator), allocatable :: node_iterator
contains
procedure :: get_node
procedure :: get_meter
procedure :: get_name
procedure :: next => next_profiler
procedure :: equals
procedure :: not_equals
generic :: operator(==) => equals
generic :: operator(/=) => not_equals
end type BaseProfilerIterator
abstract interface
function i_make_meter(this) result(meter)
import AbstractMeter
import BaseProfiler
class(AbstractMeter), allocatable :: meter
class(BaseProfiler), intent(in) :: this
end function i_make_meter
end interface
contains
subroutine start_self(this, unusable, rc)
class(BaseProfiler), target, intent(inout) :: this
class(KeywordEnforcer), optional, intent(in) :: unusable
integer, optional, intent(out) :: rc
logical :: empty_stack
this%status = 0
empty_stack = .true.
!$omp master
if (this%stack%size()/= 0) this%status = INCORRECTLY_NESTED_METERS
empty_stack = this%stack%size()== 0
if(empty_stack) call this%start(this%root_node)
!$omp end master
_ASSERT_RC(empty_stack,"Timer "//this%root_node%get_name()// " is not a fresh self start",INCORRECTLY_NESTED_METERS)
_RETURN(_SUCCESS)
_UNUSED_DUMMY(unusable)
end subroutine start_self
subroutine start_node(this, node)
class(BaseProfiler), intent(inout) :: this
class(AbstractMeterNode), target, intent(inout) :: node
class(AbstractMeter), pointer :: t
type(MeterNodePtr), pointer :: node_ptr
!$omp master
allocate(node_ptr)
node_ptr%ptr => node
call this%stack%push_back(node_ptr)
deallocate(node_ptr)
t => node%get_meter()
call t%start()
!$omp end master
end subroutine start_node
subroutine start_name(this, name, rc)
class(BaseProfiler), target, intent(inout) :: this
character(*), intent(in) :: name
integer, optional, intent(out) :: rc
class(AbstractMeter), allocatable :: m
type(MeterNodePtr), pointer :: node_ptr
class(AbstractMeterNode), pointer :: node
logical :: stack_is_not_empty
stack_is_not_empty = .true.
!$omp master
if (this%stack%empty()) this%status = INCORRECTLY_NESTED_METERS
stack_is_not_empty = .not. this%stack%empty()
if(stack_is_not_empty) then
node_ptr => this%stack%back()
node => node_ptr%ptr
if (.not. node%has_child(name)) then
m = this%make_meter()
call node%add_child(name, m) !this%make_meter())
end if
node => node%get_child(name)
end if
!$omp end master
_ASSERT_RC(stack_is_not_empty, "Timer <"//name// "> should not start when empty.",INCORRECTLY_NESTED_METERS)
call this%start(node)
_RETURN(_SUCCESS)
end subroutine start_name
subroutine stop_name(this, name, rc)
class(BaseProfiler), intent(inout) :: this
character(*), intent(in) :: name
integer, optional, intent(out) :: rc
type(MeterNodePtr), pointer :: node_ptr
class(AbstractMeterNode), pointer :: node
logical :: name_is_node_name
name_is_node_name = .true.
!$omp master
node_ptr => this%stack%back()
node => node_ptr%ptr
if (name /= node%get_name()) this%status = INCORRECTLY_NESTED_METERS
name_is_node_name = name == node%get_name()
if(name_is_node_name) call this%stop(node)
!$omp end master
_ASSERT_RC(name_is_node_name,"Timer <"//name// "> does not match start timer <"//node%get_name()//">",INCORRECTLY_NESTED_METERS)
_RETURN(_SUCCESS)
end subroutine stop_name
subroutine stop_self(this, rc)
class(BaseProfiler), intent(inout) :: this
integer, optional, intent(out) :: rc
class(MeterNodePtr), pointer :: node_ptr
class(AbstractMeterNode), pointer :: node
logical :: stack_size_is_one
stack_size_is_one = .true.
!$omp master
if (this%stack%size()/= 1) this%status = INCORRECTLY_NESTED_METERS
stack_size_is_one = this%stack%size()== 1
if(stack_size_is_one) then
node_ptr => this%stack%back()
node => node_ptr%ptr
call this%stop(node)
end if
!$omp end master
_ASSERT_RC(stack_size_is_one,"Stack not empty when timer stopped. Active timer: " // node%get_name(),INCORRECTLY_NESTED_METERS)
_RETURN(_SUCCESS)
end subroutine stop_self
subroutine stop_node(this, node)
class(BaseProfiler), intent(inout) :: this
class(AbstractMeterNode), target, intent(inout) :: node
class(AbstractMeter), pointer :: t
!$omp master
t => node%get_meter()
call t%stop()
call this%stack%pop_back()
!$omp end master
end subroutine stop_node
integer function get_num_meters(this) result(num_meters)
class(BaseProfiler), intent(in) :: this
!$omp master
num_meters = this%root_node%get_num_nodes()
!$omp end master
end function get_num_meters
subroutine finalize(this)
class(BaseProfiler), target, intent(inout) :: this
class(AbstractMeter), pointer :: t
!$omp master
call this%stack%pop_back()
t => this%root_node%get_meter()
call t%stop()
call t%finalize()
!$omp end master
end subroutine finalize
subroutine copy_profiler(new, old)
class(BaseProfiler), target, intent(inout) :: new
class(BaseProfiler), target, intent(in) :: old
type(MeterNodePtr), pointer :: node_ptr
class(AbstractMeterNode), pointer :: subnode
type(MeterNodePtr), pointer :: next_item
type(MeterNodeStackIterator) :: iter
character(:), pointer :: name
!$omp master
new%root_node = old%root_node
new%comm_world = old%comm_world
subnode => new%root_node
! Stack always starts with root node of node
if (.not. old%stack%empty()) then
iter = old%stack%begin()
node_ptr%ptr => subnode
call new%stack%push_back(node_ptr)
call iter%next()
do while (iter /= old%stack%end())
next_item => iter%of()
name => next_item%ptr%get_name()
subnode => subnode%get_child(name)
node_ptr%ptr => subnode
call new%stack%push_back(node_ptr)
call iter%next()
end do
end if
!$omp end master
end subroutine copy_profiler
integer function get_status(this) result(status)
class(BaseProfiler), intent(in) :: this
!$omp master
status = this%status
!$omp end master
end function get_status
function get_root_node(this) result(root_node)
class(AbstractMeterNode), pointer :: root_node
class(BaseProfiler), target, intent(in) :: this
!$omp master
root_node => this%root_node
!$omp end master
end function get_root_node
! TODO: move most logic to MeterNode
recursive subroutine reset(this)
class(BaseProfiler), target, intent(inout) :: this
class(AbstractMeterNodeIterator), allocatable :: iter
class(AbstractMeterNode), pointer :: node
class(AbstractMeter), pointer :: t
!$omp master
node => this%get_root_node()
iter = node%begin()
do while (iter /= node%end())
t => iter%get_meter()
call t%reset()
call iter%next()
end do
call this%start()
!$omp end master
end subroutine reset
recursive subroutine accumulate(a, b)
class(BaseProfiler), target, intent(inout) :: a
class(BaseProfiler), target, intent(in) :: b
type(MeterNodePtr), pointer :: node_ptr
class(AbstractMeterNode), pointer :: node_a, node_b
!$omp master
node_ptr => a%stack%back()
node_a => node_ptr%ptr
node_b => b%get_root_node()
call node_a%accumulate(node_b)
!$omp end master
end subroutine accumulate
function begin_profiler(this) result(iterator)
type (BaseProfilerIterator) :: iterator
class (BaseProfiler), target, intent(in) :: this
!$omp master
iterator%node_iterator = this%root_node%begin()
!$omp end master
end function begin_profiler
function end_profiler(this) result(iterator)
type (BaseProfilerIterator) :: iterator
class (BaseProfiler), target, intent(in) :: this
!$omp master
iterator%node_iterator = this%root_node%end()
!$omp end master
end function end_profiler
subroutine next_profiler(this)
class (BaseProfilerIterator), intent(inout) :: this
!$omp master
call this%node_iterator%next()
!$omp end master
end subroutine next_profiler
! Type cast to concrete class for convenience of client code.
function get_node(this) result(node)
class (MeterNode), pointer :: node
class (BaseProfilerIterator), target, intent(in) :: this
class (AbstractMeterNode), pointer :: abstract_node
!$omp master
abstract_node => this%node_iterator%get()
select type (q => abstract_node)
class is (MeterNode)
node => q
class default
error stop "missing error handling in " // __FILE__
end select
!$omp end master
end function get_node
subroutine set_node(this, node)
class(BaseProfiler), intent(inout) :: this
class(MeterNode), intent(in) :: node
!$omp master
this%root_node = node
!$omp end master
end subroutine set_node
function get_name(this) result(name)
character(:), pointer :: name
class (BaseProfilerIterator), target, intent(in) :: this
!$omp master
name => this%node_iterator%get_name()
!$omp end master
end function get_name
function get_meter(this) result(meter)
class (AdvancedMeter), pointer :: meter
class (BaseProfilerIterator), target, intent(in) :: this
class (AbstractMeter), pointer :: abstract_meter
!$omp master
abstract_meter => this%node_iterator%get_meter()
select type (q => abstract_meter)
class is (AdvancedMeter)
meter => q
class default
print*,'put error handling here'
end select
!$omp end master
end function get_meter
logical function equals(this, other)
class (BaseProfilerIterator), intent(in) :: this
class (BaseProfilerIterator), intent(in) :: other
!$omp master
equals = (this%node_iterator == other%node_iterator)
!$omp end master
end function equals
logical function not_equals(this, other)
class (BaseProfilerIterator), intent(in) :: this
class (BaseProfilerIterator), intent(in) :: other
!$omp master
not_equals = .not. (this == other)
!$omp end master
end function not_equals
integer function get_depth(this) result(depth)
class(BaseProfiler), intent(in) :: this
!$omp master
depth = this%stack%size()
!$omp end master
end function get_depth
subroutine set_comm_world(this, comm_world)
use MPI
class(BaseProfiler), intent(inout) :: this
integer, optional, intent(in) :: comm_world
!$omp master
if(present(comm_world)) then
this%comm_world = comm_world
else
this%comm_world = MPI_COMM_WORLD
endif
!$omp end master
end subroutine set_comm_world
! For debugging
subroutine print_stack(s)
type(MeterNodeStack), intent(in) :: s
type(MeterNodeStackIterator) :: iter
type(MeterNodePtr), pointer :: node_ptr
!$omp master
print*
print*,'Stack Size: ', s%size()
print*,'---------------'
associate(b => s%begin(), e => s%end())
iter = b
do while (iter /= e)
node_ptr => iter%of()
print*,node_ptr%ptr%get_name()
call iter%next()
end do
end associate
print*,'---------------'
print*
!$omp end master
end subroutine print_stack
end module mapl_BaseProfiler