ftimings_value.F90 3.71 KB
Newer Older
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
#ifdef HAVE_CONFIG_H
#include "config-f90.h"
#endif

module ftimings_value
  use ftimings_type
  implicit none
  public

  interface
    function microseconds_since_epoch() result(us) bind(C, name="ftimings_microseconds_since_epoch")
      use, intrinsic :: iso_c_binding
      implicit none
      integer(kind=C_INT64_T) :: us
    end function
  end interface

#ifdef HAVE_LIBPAPI
  logical :: papi_supported = .false.

  interface
    function current_flop_count() result(cnt) bind(C, name="ftimings_current_flop_count")
      use, intrinsic :: iso_c_binding
      implicit none
      integer(kind=C_LONG_LONG) :: cnt
    end function
  end interface
#endif

  type value_t
    integer(kind=C_INT64_T) :: micros = 0          ! Cumulative microseconds spent in this node
#ifdef HAVE_LIBPAPI
    integer(kind=C_LONG_LONG) :: flop_count = 0    ! Cumulative floating point operations done in this node
#endif
    contains
      procedure, pass :: print => print_value
  end type

  interface operator(+)
    module procedure value_add
  end interface

  interface operator(-)
    module procedure value_minus
    module procedure value_inverse
  end interface

  type(value_t), parameter :: null_value = value_t( &
                                 micros = 0 &
#ifdef HAVE_LIBPAPI
                                ,flop_count = 0 &
#endif
                              )

  contains


  ! This is the function that actually returns the current timestamp and all other counters
  function now() result(val)
    type(value_t) :: val

    ! current time
    val%micros = microseconds_since_epoch()

#ifdef HAVE_LIBPAPI
    if (papi_supported) then
      ! flop counter
      val%flop_count = current_flop_count()
    else
      val%flop_count = 0
    endif
#endif
  end function


  pure elemental function value_add(a,b) result(c)
    class(value_t), intent(in) :: a, b
    type(value_t) :: c
    c%micros = a%micros + b%micros
#ifdef HAVE_LIBPAPI
    c%flop_count = a%flop_count + b%flop_count
#endif
  end function

  pure elemental function value_minus(a,b) result(c)
    class(value_t), intent(in) :: a, b
    type(value_t) :: c
    c%micros = a%micros - b%micros
#ifdef HAVE_LIBPAPI
    c%flop_count = a%flop_count - b%flop_count
#endif
  end function

  pure elemental function value_inverse(a) result(neg_a)
    class(value_t), intent(in) :: a
    type(value_t) :: neg_a
    neg_a%micros = - a%micros
#ifdef HAVE_LIBPAPI
    neg_a%flop_count = - a%flop_count
#endif
  end function

  subroutine print_value(self, indent_level, label, total, unit)
    class(value_t), intent(in) :: self
    integer, intent(in) :: indent_level
    character(len=name_length), intent(in) :: label
    type(value_t), intent(in) :: total
    character(len=64) :: format_spec
    integer :: unit

    write(format_spec,'("(",i0,"x,""|_ "",a",i0,",2x,f12.6,5x,f8.3)")') indent_level * 2 + 1, name_length
    write(unit,format_spec,advance='no') &
      label, real(self%micros, kind=rk) * 1e-6_rk, real(self%micros, kind=rk) / real(total%micros, kind=rk)
#ifdef HAVE_LIBPAPI
    if (papi_supported) then
      write(unit,'(5x,f7.2)') real(self%flop_count, kind=C_DOUBLE) / self%micros
    else
      write(unit,'(a)') ""
    endif
#else
    write(unit,'(a)') ""
#endif
  end subroutine

  pure elemental function format_flops(flops) result(string)
    real(kind=C_DOUBLE), intent(in) :: flops
    character(len=7) :: string
    if (flops > 1e12) then
      write(string,'(f5.1,'' T'')') flops / 1e12
    else if (flops > 1e9) then
      write(string,'(f5.1,'' G'')') flops / 1e9
    else if (flops > 1e6) then
      write(string,'(f5.1,'' M'')') flops / 1e6
    else if (flops > 1e3) then
      write(string,'(f5.1,'' K'')') flops / 1e3
    else
      write(string,'(f7.1)') flops
    endif
  end function

end module