Octopus
states_elec_all_to_all_communications.F90
Go to the documentation of this file.
1!! Copyright (C) 2023 N. Tancogne-Dejean
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
21
32 use accel_oct_m
33 use batch_oct_m
34 use debug_oct_m
35 use global_oct_m
36 use math_oct_m
37 use mesh_oct_m
39 use mpi_oct_m
45
46 implicit none
47
48 private
49
50 public :: &
52
54 private
55
56 integer :: task_from
57 integer :: task_to
58
59 integer :: nbatch_to_receive
60 integer :: nbatch_to_send
61 integer :: n_comms
62
63 integer :: nblock_to_receive
64 integer :: nblock_to_send
65
66 logical :: gpu_aware = .false.
67
68 type(MPI_Request), allocatable :: send_req(:)
69 contains
74 procedure :: alloc_receive_batch => states_elec_all_to_all_communications_alloc_receive_batch
75 procedure :: get_send_indices => states_elec_all_to_all_communications_get_send_indices
76 procedure :: get_receive_indices => states_elec_all_to_all_communications_get_receive_indices
77 procedure :: dpost_all_mpi_isend => dstates_elec_all_to_all_communications_post_all_mpi_isend
78 procedure :: zpost_all_mpi_isend => zstates_elec_all_to_all_communications_post_all_mpi_isend
81 procedure :: disend_batch_to => dstates_elec_all_to_all_communications_isend_batch_to
82 procedure :: zisend_batch_to => zstates_elec_all_to_all_communications_isend_batch_to
83 procedure :: dmpi_irecv_batch => dstates_elec_all_to_all_communications_mpi_irecv_batch
84 procedure :: zmpi_irecv_batch => zstates_elec_all_to_all_communications_mpi_irecv_batch
85 procedure :: drecv_batch_from => dstates_elec_all_to_all_communications_recv_batch_from
86 procedure :: zrecv_batch_from => zstates_elec_all_to_all_communications_recv_batch_from
87 procedure :: wait_all_isend => states_elec_all_to_all_communications_wait_all_isend
89
90contains
91
92 !------------------------------------------------------------
96 subroutine states_elec_all_to_all_communications_start(this, st, task_from, task_to, gpu_aware)
97 class(states_elec_all_to_all_communications_t), intent(inout) :: this
98 type(states_elec_t), intent(in) :: st
99 integer, intent(in) :: task_from, task_to
100 logical, optional, intent(in) :: gpu_aware
101
103
104 this%task_from = task_from
105 this%task_to = task_to
106
107 this%gpu_aware = optional_default(gpu_aware, .false.)
108
109 this%nbatch_to_receive = states_elec_all_to_all_communications_eval_nreceive(st, task_from, this%nblock_to_receive)
110 this%nbatch_to_send = states_elec_all_to_all_communications_eval_nsend(st, task_to, this%nblock_to_send)
111
112 !Number of communications
113 this%n_comms = max(this%nbatch_to_send, this%nbatch_to_receive)
114
117
118 !------------------------------------------------------------
120 integer function states_elec_all_to_all_communications_eval_nreceive(st, task_from, nblock_to_receive) result(nbatch_to_receive)
121 type(states_elec_t), intent(in) :: st
122 integer, intent(in) :: task_from
123 integer, intent(out) :: nblock_to_receive
124
125 integer :: st_start, st_end, kpt_start, kpt_end, ib
128
129 nbatch_to_receive = 0
130 nblock_to_receive = 0
131
132 !What we receive for the wfn
133 if (task_from > -1) then
134 st_start = st%st_kpt_task(task_from, 1)
135 st_end = st%st_kpt_task(task_from, 2)
136 kpt_start = st%st_kpt_task(task_from, 3)
137 kpt_end = st%st_kpt_task(task_from, 4)
138
139 nblock_to_receive = 0
140 do ib = 1, st%group%nblocks
141 if (st%group%block_range(ib, 1) >= st_start .and. st%group%block_range(ib, 2) <= st_end) then
142 nblock_to_receive = nblock_to_receive + 1
143 end if
144 end do
145 nbatch_to_receive = nblock_to_receive * (kpt_end-kpt_start+1)
146 end if
147
148 write(message(1), '(a,i5,a,i5,a,i5)') 'Debug: Task ', st%st_kpt_mpi_grp%rank, ' will receive ', &
149 nbatch_to_receive, ' batches from task ', task_from
150 call messages_info(1, all_nodes=.true., debug_only=.true.)
155 !------------------------------------------------------------
157 integer function states_elec_all_to_all_communications_eval_nsend(st, task_to, nblock_to_send) result(nbatch_to_send)
158 type(states_elec_t), intent(in) :: st
159 integer, intent(in) :: task_to
160 integer, intent(out) :: nblock_to_send
164 nbatch_to_send = 0
165 nblock_to_send = 0
167 if (task_to > -1) then
168 nblock_to_send = (st%group%block_end-st%group%block_start+1)
169 nbatch_to_send = nblock_to_send*(st%d%kpt%end-st%d%kpt%start+1)
170 end if
172 write(message(1), '(a,i5,a,i5,a,i5)') 'Debug: Task ', st%st_kpt_mpi_grp%rank, ' will send ', nbatch_to_send, &
173 ' batches to task ', task_to
174 call messages_info(1, all_nodes=.true., debug_only=.true.)
179 !------------------------------------------------------------
181 integer pure function states_elec_all_to_all_communications_get_ncom(this) result(n_comms)
183
184 n_comms = this%n_comms
186
187 !------------------------------------------------------------
189 integer pure function states_elec_all_to_all_communications_get_nreceive(this) result(nbatch_to_receive)
190 class(states_elec_all_to_all_communications_t), intent(in) :: this
192 nbatch_to_receive = this%nbatch_to_receive
194
195 !------------------------------------------------------------
197 integer pure function states_elec_all_to_all_communications_get_nsend(this) result(nbatch_to_send)
198 class(states_elec_all_to_all_communications_t), intent(in) :: this
199
200 nbatch_to_send = this%nbatch_to_send
202
203 !------------------------------------------------------------
205 subroutine states_elec_all_to_all_communications_alloc_receive_batch(this, st, icom, np, psib)
206 class(states_elec_all_to_all_communications_t), intent(in) :: this
207 type(states_elec_t), intent(in) :: st
208 integer, intent(in) :: icom
209 integer, intent(in) :: np
210 type(wfs_elec_t), intent(out) :: psib
211
212 integer :: block_id, ib, ik
213
216 ! Given the icom, returns the id of the block of state communicated
217 block_id = mod(icom-1, this%nblock_to_receive)+1
218 ik = int((icom-block_id)/this%nblock_to_receive) + st%st_kpt_task(this%task_from, 3)
219 ib = block_id - 1 + st%group%iblock(st%st_kpt_task(this%task_from, 1))
220
221 write(message(1), '(a,i5,a,i5,a,i5)') 'Debug: Task ', st%st_kpt_mpi_grp%rank, ' allocates memory for block ', &
222 ib, ' and k-point ', ik
223 call messages_info(1, all_nodes=.true., debug_only=.true.)
224
225 call states_elec_parallel_allocate_batch(st, psib, np, ib, ik, packed=.true.)
226
227 ! For CUDA-aware MPI, the batch must be on GPU to receive directly in the buffer.
228 if (this%gpu_aware) then
229 call psib%do_pack(batch_device_packed, copy = .false.)
230 end if
231
234
235 !------------------------------------------------------------
237 subroutine states_elec_all_to_all_communications_get_send_indices(this, st, icom, ib, ik)
238 class(states_elec_all_to_all_communications_t), intent(in) :: this
239 type(states_elec_t), intent(in) :: st
240 integer, intent(in) :: icom
241 integer, intent(out) :: ib
242 integer, intent(out) :: ik
243
245
246 ! Given the icom, returns the id of the block of state communicated
247 ib = mod(icom-1, this%nblock_to_send) + 1
248 ik = int((icom-ib)/this%nblock_to_send) + st%d%kpt%start
249 ib = ib - 1 + st%group%iblock(st%st_start)
250
251 write(message(1), '(a,i5,a,i5,a,i5)') 'Debug: Task ', st%st_kpt_mpi_grp%rank, ' will send the block ', &
252 ib, ' with k-point ', ik
253 call messages_info(1, all_nodes=.true., debug_only=.true.)
254
257
258 !------------------------------------------------------------
260 subroutine states_elec_all_to_all_communications_get_receive_indices(this, st, icom, ib, ik)
261 class(states_elec_all_to_all_communications_t), intent(in) :: this
262 type(states_elec_t), intent(in) :: st
263 integer, intent(in) :: icom
264 integer, intent(out) :: ib
265 integer, intent(out) :: ik
266
268
269 ! Given the icom, returns the id of the block of state communicated
270 ib = mod(icom-1, this%nblock_to_receive)+1
271 ik = int((icom-ib)/this%nblock_to_receive) + st%st_kpt_task(this%task_from, 3)
272 ib = ib - 1 + st%group%iblock(st%st_kpt_task(this%task_from, 1))
273
274 if (debug%info) then
275 write(message(1), '(a,i5,a,i5,a,i5)') 'Task ', st%st_kpt_mpi_grp%rank, ' will receive the block ', &
276 ib, ' with k-point ', ik
277 call messages_info(1, all_nodes=.true.)
278 end if
279
282
283 !------------------------------------------------------------
286 class(states_elec_all_to_all_communications_t), intent(inout) :: this
287 type(states_elec_t), intent(in) :: st
288
290 call profiling_in("ALL_TO_ALL_COMM")
291
292 if (allocated(this%send_req)) then
293
294 call st%st_kpt_mpi_grp%wait(this%nbatch_to_send, this%send_req)
295
296 safe_deallocate_a(this%send_req)
297
298 end if
299
300 call profiling_out("ALL_TO_ALL_COMM")
303
304
305
306#include "undef.F90"
307#include "real.F90"
308#include "states_elec_all_to_all_communications_inc.F90"
309
310#include "undef.F90"
311#include "complex.F90"
312#include "states_elec_all_to_all_communications_inc.F90"
313#include "undef.F90"
314
316
317!! Local Variables:
318!! mode: f90
319!! coding: utf-8
320!! End:
This module implements batches of mesh functions.
Definition: batch.F90:135
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
This module provides routines for communicating all batches in a ring-pattern scheme.
subroutine states_elec_all_to_all_communications_get_receive_indices(this, st, icom, ib, ik)
Given the icom step, returns the block and k-point indices to be received.
integer function states_elec_all_to_all_communications_eval_nsend(st, task_to, nblock_to_send)
How many batches we will send from task_send.
subroutine zstates_elec_all_to_all_communications_isend_batch_to(this, st, np, psib, node_to, icom, send_req)
Post a single MPI isend for an explicit batch to node_to.
subroutine zstates_elec_all_to_all_communications_mpi_irecv_batch(this, st, np, node_fr, icom, psib_receiv, recv_req)
Allocate a batch and post the MPI_Irecv for it. The caller must wait on recv_req before using the bat...
subroutine states_elec_all_to_all_communications_wait_all_isend(this, st)
Do a MPI waitall for the isend requests.
subroutine zstates_elec_all_to_all_communications_post_all_mpi_isend(this, st, np, node_to)
Post all isend commands for all batches of a given task.
integer pure function states_elec_all_to_all_communications_get_nreceive(this)
Returns the number of receiv calls.
subroutine states_elec_all_to_all_communications_alloc_receive_batch(this, st, icom, np, psib)
Given the icom step, allocate the receiv buffer (wfs_elec_t)
subroutine dstates_elec_all_to_all_communications_isend_batch(this, st, np, ib_send, ik_send, node_to, icom, send_req)
Post a single MPI isend for the batch (ib_send, ik_send) to node_to.
integer pure function states_elec_all_to_all_communications_get_ncom(this)
Returns the number of communications.
subroutine dstates_elec_all_to_all_communications_post_all_mpi_isend(this, st, np, node_to)
Post all isend commands for all batches of a given task.
subroutine states_elec_all_to_all_communications_get_send_indices(this, st, icom, ib, ik)
Given the icom step, returns the block and k-point indices to be sent.
integer function states_elec_all_to_all_communications_eval_nreceive(st, task_from, nblock_to_receive)
How many batches we will receive from task_from.
subroutine states_elec_all_to_all_communications_start(this, st, task_from, task_to, gpu_aware)
Given a task to send to, and a task to receive from, initializes a states_elec_all_to_all_communicati...
subroutine dstates_elec_all_to_all_communications_mpi_irecv_batch(this, st, np, node_fr, icom, psib_receiv, recv_req)
Allocate a batch and post the MPI_Irecv for it. The caller must wait on recv_req before using the bat...
subroutine zstates_elec_all_to_all_communications_recv_batch_from(this, st, np, psib, node_fr, icom)
Blocking MPI recv into an already-allocated batch from node_fr.
subroutine dstates_elec_all_to_all_communications_isend_batch_to(this, st, np, psib, node_to, icom, send_req)
Post a single MPI isend for an explicit batch to node_to.
integer pure function states_elec_all_to_all_communications_get_nsend(this)
Returns the number send calls.
subroutine dstates_elec_all_to_all_communications_recv_batch_from(this, st, np, psib, node_fr, icom)
Blocking MPI recv into an already-allocated batch from node_fr.
subroutine zstates_elec_all_to_all_communications_isend_batch(this, st, np, ib_send, ik_send, node_to, icom, send_req)
Post a single MPI isend for the batch (ib_send, ik_send) to node_to.
This module provides routines for communicating states when using states parallelization.
The states_elec_t class contains all electronic wave functions.
int true(void)