Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
comm.F90
Go to the documentation of this file.
1module comm
2 use mpi_f08, only : mpi_comm, mpi_datatype, mpi_initialized, mpi_init_thread, &
3 mpi_init, mpi_thread_single, mpi_thread_funneled, &
4 mpi_thread_serialized, mpi_thread_multiple, mpi_comm_rank, &
5 mpi_comm_split, mpi_comm_dup, mpi_barrier, mpi_comm_free, mpi_finalize, &
6 mpi_comm_world, mpi_double_precision, mpi_real, mpi_comm_size, &
7 mpi_query_thread
8 use utils, only : neko_error
10 use shmem
11 !$ use omp_lib
12 implicit none
13 private
14
15 interface
16 subroutine neko_comm_wrapper_init(fcomm) &
17 bind(c, name='neko_comm_wrapper_init')
18 use, intrinsic :: iso_c_binding, only : c_int
19 integer(c_int), value :: fcomm
20 end subroutine neko_comm_wrapper_init
21
22#ifdef HAVE_NVSHMEM
23 subroutine neko_comm_nvshmem_init() &
24 bind(c, name='neko_comm_nvshmem_init')
25 end subroutine neko_comm_nvshmem_init
26
27 subroutine neko_comm_nvshmem_finalize() &
28 bind(c, name='neko_comm_nvshmem_finalize')
29 end subroutine neko_comm_nvshmem_finalize
30#endif
31
32#if defined(HAVE_NCCL) || defined(HAVE_RCCL)
33 subroutine neko_comm_nccl_init() &
34 bind(c, name='neko_comm_nccl_init')
35 end subroutine neko_comm_nccl_init
36
37 subroutine neko_comm_nccl_finalize() &
38 bind(c, name='neko_comm_nccl_finalize')
39 end subroutine neko_comm_nccl_finalize
40#endif
41
42 end interface
43
44
46 type(mpi_comm), public :: neko_comm
47 type(mpi_comm), public :: neko_global_comm
48
50#ifdef HAVE_MPI_PARAM_DTYPE
51 type(mpi_datatype), public, parameter :: mpi_real_precision = mpi_double_precision
52 type(mpi_datatype), public, parameter :: mpi_extra_precision = mpi_double_precision
53#else
54 type(mpi_datatype), public :: mpi_real_precision
55 type(mpi_datatype), public :: mpi_extra_precision
56#endif
57
59 integer, public :: pe_rank
60
62 integer, public :: pe_size = 0
63
65 logical, public :: nio
66
68 integer, public :: global_pe_rank
69
71 integer, public :: global_pe_size = 0
72
74 integer, public :: neko_mpi_thread_provided
75
76 public :: comm_init, comm_free, is_mpmd
77
78contains
79
82 pure function is_mpmd() result(mpmd)
83 logical :: mpmd
84
85 mpmd = global_pe_size .gt. 0 .and. pe_size .ne. global_pe_size
86
87 end function is_mpmd
88
89 subroutine comm_init
90 integer :: ierr
91 logical :: initialized
92 integer :: provided, nthrds
93 integer :: color = 0
94 integer :: envvar_len
95 character(len=255) :: color_str
96 character(len=32) :: thread_str
97 integer :: thread_envvar_len
98 integer :: requested_thread_level
99 logical :: user_thread_level
100#ifdef HAVE_OPENSHMEM
101 integer :: shmem_ierr
102 integer :: shmem_requested
103#endif
104
105 pe_rank = -1
106 pe_size = 0
107 nio = .false.
108
109 call mpi_initialized(initialized, ierr)
110
111 call get_environment_variable("NEKO_COMM_ID", color_str, envvar_len)
112 if (envvar_len .gt. 0) then
113 read(color_str(1:envvar_len), *) color
114 else
115 color = 0
116 end if
117
118 nthrds = 1
119 !$omp parallel
120 !$omp master
121 !$ nthrds = omp_get_num_threads()
122 !$omp end master
123 !$omp end parallel
124
125 call get_environment_variable("NEKO_MPI_THREAD_LEVEL", thread_str, &
126 thread_envvar_len)
127 user_thread_level = thread_envvar_len .gt. 0
128 if (user_thread_level) then
129 select case (trim(adjustl(thread_str(1:thread_envvar_len))))
130 case ("single", "SINGLE")
131 requested_thread_level = mpi_thread_single
132 case ("funneled", "FUNNELED")
133 requested_thread_level = mpi_thread_funneled
134 case ("serialized", "SERIALIZED")
135 requested_thread_level = mpi_thread_serialized
136 case ("multiple", "MULTIPLE")
137 requested_thread_level = mpi_thread_multiple
138 case default
139 call neko_error('Unknown NEKO_MPI_THREAD_LEVEL: '// &
140 trim(thread_str(1:thread_envvar_len)))
141 end select
142 end if
143
144 if (.not.initialized) then
145 if (user_thread_level) then
146 if (requested_thread_level .eq. mpi_thread_single) then
147 call mpi_init(ierr)
148 provided = mpi_thread_single
149 else
150 call mpi_init_thread(requested_thread_level, provided, ierr)
151 if (provided .lt. requested_thread_level) then
152 call neko_error('Requested MPI thread level not provided')
153 end if
154 end if
155 else if (nthrds .gt. 1) then
156 call mpi_init_thread(mpi_thread_multiple, provided, ierr)
157 if (provided .lt. mpi_thread_multiple) then
158 ! MPI_THREAD_MULTIPLE is required for mt. device backends. For
159 ! host backends the gather-scatter MPI calls are issued from the
160 ! OpenMP master thread, so MPI_THREAD_SERIALIZED (or FUNNELED) is
161 ! sufficient as a last resort.
162 if (neko_bcknd_device .eq. 1) then
163 call neko_error('Invalid thread support provided by MPI')
164 else if (provided .lt. mpi_thread_funneled) then
165 call neko_error('Invalid thread support provided by MPI')
166 end if
167 end if
168 else
169 call mpi_init(ierr)
170 end if
171 else
172 call mpi_query_thread(provided, ierr)
173 end if
174
175 neko_mpi_thread_provided = provided
176
177#ifndef HAVE_MPI_PARAM_DTYPE
178 mpi_real_precision = mpi_double_precision
179 mpi_extra_precision = mpi_double_precision
180#endif
181
182
183#ifdef HAVE_ADIOS2
184 ! We split the communicator it to work asynchronously (MPMD)
185 call mpi_comm_rank(mpi_comm_world, pe_rank, ierr)
186 call mpi_comm_split(mpi_comm_world, 0, pe_rank, neko_global_comm, ierr)
187#else
188 ! Original version duplicates the communicator:
189 call mpi_comm_dup(mpi_comm_world, neko_global_comm, ierr)
190#endif
191
192 call mpi_comm_rank(neko_global_comm, global_pe_rank, ierr)
193 call mpi_comm_size(neko_global_comm, global_pe_size, ierr)
194 if (envvar_len .gt. 0) then
195 call mpi_comm_split(neko_global_comm, color, global_pe_rank, &
196 neko_comm, ierr)
197 else
198 call mpi_comm_dup(neko_global_comm, neko_comm, ierr)
199 end if
200 call mpi_comm_rank(neko_comm, pe_rank, ierr)
201 call mpi_comm_size(neko_comm, pe_size, ierr)
202
203 ! Setup C/C++ wrapper
205
206
207#ifdef HAVE_NVSHMEM
208 ! Setup NVSHMEM (if requested)
209 call neko_comm_nvshmem_init()
210#endif
211
212#if defined(HAVE_NCCL) | defined(HAVE_RCCL)
213 ! Setup NCCL (if requested)
214 call neko_comm_nccl_init()
215#endif
216
217#ifdef HAVE_OPENSHMEM
218 ! Setup OpenSHMEM (if requested)
219 if (user_thread_level) then
220 select case (requested_thread_level)
221 case (mpi_thread_single)
222 shmem_requested = shmem_thread_single
223 case (mpi_thread_funneled)
224 shmem_requested = shmem_thread_funneled
225 case (mpi_thread_serialized)
226 shmem_requested = shmem_thread_serialized
227 case (mpi_thread_multiple)
228 shmem_requested = shmem_thread_multiple
229 end select
230 if (shmem_requested .eq. shmem_thread_single) then
231 call shmem_init()
232 else
233 shmem_ierr = shmem_init_thread(shmem_requested, provided)
234 call shmem_check_thread_level(provided)
235 end if
236 else if (nthrds .gt. 1) then
237 ! One shot only: OpenSHMEM allows a single initialisation call, so a
238 ! provided level below the requested one cannot be retried with a
239 ! second shmem_init_thread -- Cray LIBSMA aborts the job when it sees
240 ! one ("multiple initializations are done for multithreading"). Ask
241 ! for MULTIPLE and take whatever comes back.
242 shmem_ierr = shmem_init_thread(shmem_thread_multiple, provided)
243 call shmem_check_thread_level(provided)
244 else
245 call shmem_init()
246 end if
247#endif
248
249
250 end subroutine comm_init
251
252#ifdef HAVE_OPENSHMEM
253
265 subroutine shmem_check_thread_level(provided)
266 integer, intent(in) :: provided
267
268 if (neko_bcknd_device .eq. 1 .and. &
269 provided .lt. shmem_thread_multiple) then
270 call neko_error('Invalid thread support provided by SHMEM')
271 end if
272
273 end subroutine shmem_check_thread_level
274#endif
275
276 subroutine comm_free
277 integer :: ierr
278
279 call mpi_barrier(neko_comm, ierr)
280 call mpi_comm_free(neko_comm, ierr)
281 call mpi_comm_free(neko_global_comm, ierr)
282
283#ifdef HAVE_NCCL
284 call neko_comm_nccl_finalize()
285#endif
286
287#ifdef HAVE_NVSHMEM
288 call neko_comm_nvshmem_finalize()
289#endif
290
291#ifdef HAVE_OPENSHMEM
292 call shmem_finalize()
293#endif
294
295 call mpi_finalize(ierr)
296
297 end subroutine comm_free
298
299end module comm
Definition comm.F90:1
subroutine, public comm_free
Definition comm.F90:277
subroutine, public comm_init
Definition comm.F90:90
logical, public nio
I/O node.
Definition comm.F90:65
type(mpi_comm), public neko_global_comm
Definition comm.F90:47
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:54
integer, public global_pe_rank
Global MPI rank.
Definition comm.F90:68
integer, public pe_size
MPI size of communicator.
Definition comm.F90:62
integer, public pe_rank
MPI rank.
Definition comm.F90:59
integer, public global_pe_size
Global MPI size of communicator.
Definition comm.F90:71
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
integer, public neko_mpi_thread_provided
Thread support provided by the MPI library.
Definition comm.F90:74
subroutine shmem_check_thread_level(provided)
Decide whether the thread level an OpenSHMEM library handed back is usable, given how Neko drives it.
Definition comm.F90:266
type(mpi_datatype), public mpi_extra_precision
Definition comm.F90:55
pure logical function, public is_mpmd()
Whether this is one of several simulations coupled in an MPMD run, that is, whether Neko's communicat...
Definition comm.F90:83
Build configurations.
integer, parameter neko_bcknd_device
Fortran bindings to SHMEM's C API.
Definition shmem.F90:34
@ shmem_thread_serialized
Definition shmem.F90:56
@ shmem_thread_multiple
Definition shmem.F90:57
@ shmem_thread_single
Definition shmem.F90:54
@ shmem_thread_funneled
Definition shmem.F90:55
Utilities.
Definition utils.f90:35