GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.6% 39 / 0 / 44
Functions: 85.7% 6 / 0 / 7
Branches: 62.5% 20 / 0 / 32

tensorprod/m_tensorprod_shared.F90
Line Branch Exec Source
1 !> Module for initialising arrays based on shared memory using MPI shared memory windows
2 module m_tensorprod_shared
3 #include "petsc.fi"
4 use m_common, only: wp
5 use m_domain_decomp, only: TensorProdDomain
6 use m_tensorprod_indices, only: TensorProdIndices
7 implicit none
8
9 private
10 public :: SharedMemoryWindow
11
12 !> Type for managing a shared memory array using MPI shared memory windows
13 type SharedMemoryWindow
14 !> Pointer to the shared memory array
15 real(wp), contiguous, pointer :: window(:) => null()
16
17 !> MPI window identifier for the shared memory window
18 integer :: win_shmem_id
19
20 !> MPI communicator for the shared memory domain
21 integer :: comm
22
23 !> Rank of this process in the shared memory communicator
24 integer :: my_rank
25
26 !> Number of ranks sharing this memory (size of comm)
27 integer :: nr_ranks
28 contains
29 procedure, private :: init_shared_memory_window_tpdomain
30 procedure, private :: init_shared_memory_window_base
31 generic :: init => init_shared_memory_window_tpdomain, init_shared_memory_window_base
32 procedure :: destroy => destroy_shared_memory_window
33 procedure :: fence
34 procedure :: leader
35 procedure :: cat
36 end type SharedMemoryWindow
37
38 contains
39
40 !> Initialize a array in shared memory using a MPI shared memory window
41 !>
42 !> @param[out] this SharedMemoryWindow object
43 !> @param[in] nr_elements Number of elements in the shared memory array
44 !> @param[in] domain TensorProdDomain object defining the shared memory communicator
45 !>
46 !> @note The memory is shared among all processes in the domain%comm_shmem MPI communicator
47 8578 subroutine init_shared_memory_window_tpdomain(this, nr_elements, domain)
48 implicit none
49
50 class(SharedMemoryWindow), intent(inout) :: this
51 integer, intent(in) :: nr_elements
52 type(TensorProdDomain), intent(in) :: domain
53
54 8578 call this%init_shared_memory_window_base(nr_elements, domain%comm_shmem, domain%my_shmem_rank)
55 8578 end subroutine init_shared_memory_window_tpdomain
56
57 !> Initialize a array in shared memory using a MPI shared memory window
58 !>
59 !> @param[out] this SharedMemoryWindow object
60 !> @param[in] nr_elements Number of elements in the shared memory array
61 !> @param[in] comm MPI communicator for the shared memory domain (each rank on this communicator must be on the same node)
62 !> @param[in] my_rank Rank of this process in the shared memory communicator
63 20572 subroutine init_shared_memory_window_base(this, nr_elements, comm, my_rank)
64 implicit none
65
66 class(SharedMemoryWindow), intent(inout) :: this
67 integer, intent(in) :: nr_elements
68 integer, intent(in) :: comm
69 integer, intent(in) :: my_rank
70
71 ! Shared memory window variables
72 integer(KIND=MPI_ADDRESS_KIND) :: window_size, baseptr_addr
73 type(c_ptr) :: baseptr_c
74 integer :: disp_unit, ierr
75
76 10286 call this%destroy()
77
78 10286 this%comm = comm
79 10286 this%my_rank = my_rank
80
81 ! Get the number of ranks in the communicator
82
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 10286 times.
10286 PetscCallMPI(MPI_Comm_size(this%comm, this%nr_ranks, ierr))
83
84 ! Only the leader (my_rank == 0) allocates; others allocate 0 bytes
85 10286 disp_unit = int(storage_size(1.0_wp) / 8, MPI_ADDRESS_KIND) ! Size in bytes
86
1/2
✓ Branch 6 → 7 taken 10286 times.
✗ Branch 6 → 8 not taken.
10286 if (this%my_rank == 0) then
87 10286 window_size = int(nr_elements, MPI_ADDRESS_KIND) * disp_unit
88 else
89 window_size = 0_MPI_ADDRESS_KIND
90 end if
91
92 ! Create shared memory window on the node communicator
93
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 10286 times.
10286 PetscCallMPI(MPI_Win_allocate_shared(window_size, disp_unit, MPI_INFO_NULL, \
94 this%comm, baseptr_addr, this%win_shmem_id, ierr))
95
96 ! Non-leaders query the address of the leader's memory
97
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 16 taken 10286 times.
10286 if (this%my_rank /= 0) then
98 PetscCallMPI(MPI_Win_shared_query(this%win_shmem_id, 0, window_size, disp_unit, baseptr_addr, ierr))
99 end if
100
101 ! Convert integer address to C pointer, then to Fortran pointer
102 10286 baseptr_c = transfer(baseptr_addr, baseptr_c)
103
2/2
✓ Branch 17 → 18 taken 10286 times.
✓ Branch 17 → 19 taken 10286 times.
20572 call c_f_pointer(baseptr_c, this%window, [nr_elements])
104
105 10286 call this%fence()
106 end subroutine init_shared_memory_window_base
107
108 !> Destroy a shared memory array and free the associated MPI window
109 !>
110 !> @param[inout] this SharedMemoryWindow object
111 28508 subroutine destroy_shared_memory_window(this)
112 implicit none
113
114 class(SharedMemoryWindow), intent(inout) :: this
115 integer :: ierr
116
117
2/2
✓ Branch 2 → 3 taken 7708 times.
✓ Branch 2 → 7 taken 13092 times.
20800 if (.not. associated(this%window)) return
118
119 ! Free the shared memory window
120
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7708 times.
7708 PetscCallMPI(MPI_Win_free(this%win_shmem_id, ierr))
121
122 7708 nullify (this%window)
123 end subroutine destroy_shared_memory_window
124
125 !> Synchronize access to the shared memory window
126 !>
127 !> @param[inout] this SharedMemoryWindow object
128 48768 subroutine fence(this)
129 implicit none
130
131 class(SharedMemoryWindow), intent(inout) :: this
132 integer :: ierr
133
134
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 48768 times.
48768 PetscCallMPI(MPI_Win_fence(0, this%win_shmem_id, ierr))
135 end subroutine fence
136
137 !> Check if this process is the leader in the shared memory communicator
138 !>
139 !> @param[in] this SharedMemoryWindow object
140 !> @return .true. if this process is the leader (rank 0), .false. otherwise
141 23320 pure logical function leader(this)
142 implicit none
143 class(SharedMemoryWindow), intent(in) :: this
144 23320 leader = (this%my_rank == 0)
145 23320 end function leader
146
147 !> Concatenate two shared memory windows (not implemented)
148 !>
149 !> @param[inout] this SharedMemoryWindow object to be concatenated to (output is [this, other])
150 !> @param[in] other SharedMemoryWindow object to concatenate from
151 70 subroutine cat(this, other)
152 implicit none
153 class(SharedMemoryWindow), intent(inout) :: this
154 class(SharedMemoryWindow), intent(in) :: other
155
156 type(SharedMemoryWindow) :: temp_window
157
158 70 if (this%my_rank /= other%my_rank) then
159 error stop "SharedMemoryWindow::cat: both windows must have the same rank in their communicators"
160 end if
161
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 70 times.
70 if (this%comm /= other%comm) then
162 error stop "SharedMemoryWindow::cat: both windows must have the same communicator"
163 end if
164
165 70 call temp_window%init(size(this%window), this%comm, this%my_rank)
166
167
3/4
✓ Branch 8 → 9 taken 70 times.
✗ Branch 8 → 12 not taken.
✓ Branch 10 → 11 taken 212520 times.
✓ Branch 10 → 12 taken 70 times.
212590 if (this%leader()) temp_window%window(:) = this%window(:)
168 70 call this%fence()
169
170 70 call this%destroy()
171 70 call this%init(size(temp_window%window) + size(other%window), temp_window%comm, temp_window%my_rank)
172
173
1/2
✓ Branch 16 → 17 taken 70 times.
✗ Branch 16 → 23 not taken.
70 if (this%leader()) then
174
2/2
✓ Branch 18 → 19 taken 212520 times.
✓ Branch 18 → 20 taken 70 times.
212590 this%window(1:size(temp_window%window)) = temp_window%window
175
2/2
✓ Branch 21 → 22 taken 78912 times.
✓ Branch 21 → 23 taken 70 times.
78982 this%window(size(temp_window%window) + 1:size(this%window)) = other%window
176 end if
177 70 call this%fence()
178
179 70 call temp_window%destroy()
180
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 70 times.
70 end subroutine cat
181
182 end module m_tensorprod_shared
183