1 /*
2 Build a few basic tools to help with partitioned domains.
3
4 1)
5 On each processor, have a DomainExchangerTopology.
6 This is a doubly-connected edge list which enumerates the
7 communication paths between connected processors. By numbering
8 these paths we can always uniquely assign message identifiers.
9
10 edge
11 10
12 proc ---------> proc
13 0 <-------- 1
14 11
15 twin
16
17 Eg: Proc 0 send to proc 1 with message id is 10. To receive the correct
18 message, proc 1 looks for the edge connected to proc 0, and then the
19 message id comes from the twin of that edge
20
21 2)
22 A DomainExchangerArrayPacker.
23 A little function which given a piece of data, will memcpy the data into
24 an array (which will be sent to procs) into the correct place.
25
26 On Proc 1 we sent data to procs 0,2,3. The data is on different lengths.
27 All data gets jammed into single array. Need to "jam" data into correct locations
28 The Packer knows how much is to going to each processor and keeps track of the inserts
29 so as to avoid ever packing TOO much into one slot, and inevatbly corrupting some memory
30
31 data to 0 data to 2 data to 3
32
33 |--------|-----------------|--|
34
35 User has to unpack message themselves. I can get you the pointer for each i
36 entry, but you'll have to cast it to the appropriate data type.
37
38 Phase A: Build topology
39
40 Phase B: Define message lengths
41
42 Phase C: Pack data
43
44 Phase D: Send data
45
46 + Constructor
47 DMSwarmDataExCreate()
48 + Phase A
49 DMSwarmDataExTopologyInitialize()
50 DMSwarmDataExTopologyAddNeighbour()
51 DMSwarmDataExTopologyAddNeighbour()
52 DMSwarmDataExTopologyFinalize()
53 + Phase B
54 DMSwarmDataExZeroAllSendCount()
55 DMSwarmDataExAddToSendCount()
56 DMSwarmDataExAddToSendCount()
57 DMSwarmDataExAddToSendCount()
58 + Phase C
59 DMSwarmDataExPackInitialize()
60 DMSwarmDataExPackData()
61 DMSwarmDataExPackData()
62 DMSwarmDataExPackFinalize()
63 +Phase D
64 DMSwarmDataExBegin()
65 ... perform any calculations ...
66 DMSwarmDataExEnd()
67
68 ... user calls any getters here ...
69
70 */
71 #include <petscvec.h>
72 #include <petscmat.h>
73 #include <petsc/private/petscimpl.h>
74
75 #include "../src/dm/impls/swarm/data_ex.h"
76
77 const char *status_names[] = {"initialized", "finalized", "unknown"};
78
79 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerTopologySetup;
80 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerBegin;
81 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerEnd;
82 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerSendCount;
83 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerPack;
84
DMSwarmDataExCreate(MPI_Comm comm,const PetscInt count,DMSwarmDataEx * ex)85 PetscErrorCode DMSwarmDataExCreate(MPI_Comm comm, const PetscInt count, DMSwarmDataEx *ex)
86 {
87 DMSwarmDataEx d;
88
89 PetscFunctionBegin;
90 PetscCall(PetscNew(&d));
91 PetscCallMPI(MPI_Comm_dup(comm, &d->comm));
92 PetscCallMPI(MPI_Comm_rank(d->comm, &d->rank));
93
94 d->instance = count;
95
96 d->topology_status = DEOBJECT_STATE_UNKNOWN;
97 d->message_lengths_status = DEOBJECT_STATE_UNKNOWN;
98 d->packer_status = DEOBJECT_STATE_UNKNOWN;
99 d->communication_status = DEOBJECT_STATE_UNKNOWN;
100
101 d->n_neighbour_procs = -1;
102 d->neighbour_procs = NULL;
103
104 d->messages_to_be_sent = NULL;
105 d->message_offsets = NULL;
106 d->messages_to_be_recvieved = NULL;
107
108 d->unit_message_size = (size_t)-1;
109 d->send_message = NULL;
110 d->send_message_length = -1;
111 d->recv_message = NULL;
112 d->recv_message_length = -1;
113 d->total_pack_cnt = -1;
114 d->pack_cnt = NULL;
115
116 d->send_tags = NULL;
117 d->recv_tags = NULL;
118
119 d->_stats = NULL;
120 d->_requests = NULL;
121 *ex = d;
122 PetscFunctionReturn(PETSC_SUCCESS);
123 }
124
125 /*
126 This code is horrible, who let it get into main.
127
128 Should be printing to a viewer, should not be using PETSC_COMM_WORLD
129
130 */
DMSwarmDataExView(DMSwarmDataEx d)131 PetscErrorCode DMSwarmDataExView(DMSwarmDataEx d)
132 {
133 PetscMPIInt p;
134
135 PetscFunctionBegin;
136 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "DMSwarmDataEx: instance=%" PetscInt_FMT "\n", d->instance));
137 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " topology status: %s \n", status_names[d->topology_status]));
138 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " message lengths status: %s \n", status_names[d->message_lengths_status]));
139 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " packer status status: %s \n", status_names[d->packer_status]));
140 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " communication status: %s \n", status_names[d->communication_status]));
141
142 if (d->topology_status == DEOBJECT_FINALIZED) {
143 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " Topology:\n"));
144 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] neighbours: %d \n", d->rank, d->n_neighbour_procs));
145 for (p = 0; p < d->n_neighbour_procs; p++) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] neighbour[%d] = %d \n", d->rank, p, d->neighbour_procs[p]));
146 PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout));
147 }
148
149 if (d->message_lengths_status == DEOBJECT_FINALIZED) {
150 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " Message lengths:\n"));
151 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] atomic size: %ld \n", d->rank, (long int)d->unit_message_size));
152 for (p = 0; p < d->n_neighbour_procs; p++) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] >>>>> ( %" PetscInt_FMT " units :: tag = %d) >>>>> [%d] \n", d->rank, d->messages_to_be_sent[p], d->send_tags[p], d->neighbour_procs[p]));
153 for (p = 0; p < d->n_neighbour_procs; p++) {
154 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] <<<<< ( %" PetscInt_FMT " units :: tag = %d) <<<<< [%d] \n", d->rank, d->messages_to_be_recvieved[p], d->recv_tags[p], d->neighbour_procs[p]));
155 }
156 PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout));
157 }
158 PetscFunctionReturn(PETSC_SUCCESS);
159 }
160
DMSwarmDataExDestroy(DMSwarmDataEx d)161 PetscErrorCode DMSwarmDataExDestroy(DMSwarmDataEx d)
162 {
163 PetscFunctionBegin;
164 PetscCallMPI(MPI_Comm_free(&d->comm));
165 if (d->neighbour_procs) PetscCall(PetscFree(d->neighbour_procs));
166 if (d->messages_to_be_sent) PetscCall(PetscFree(d->messages_to_be_sent));
167 if (d->message_offsets) PetscCall(PetscFree(d->message_offsets));
168 if (d->messages_to_be_recvieved) PetscCall(PetscFree(d->messages_to_be_recvieved));
169 if (d->send_message) PetscCall(PetscFree(d->send_message));
170 if (d->recv_message) PetscCall(PetscFree(d->recv_message));
171 if (d->pack_cnt) PetscCall(PetscFree(d->pack_cnt));
172 if (d->send_tags) PetscCall(PetscFree(d->send_tags));
173 if (d->recv_tags) PetscCall(PetscFree(d->recv_tags));
174 if (d->_stats) PetscCall(PetscFree(d->_stats));
175 if (d->_requests) PetscCall(PetscFree(d->_requests));
176 PetscCall(PetscFree(d));
177 PetscFunctionReturn(PETSC_SUCCESS);
178 }
179
180 /* === Phase A === */
181
DMSwarmDataExTopologyInitialize(DMSwarmDataEx d)182 PetscErrorCode DMSwarmDataExTopologyInitialize(DMSwarmDataEx d)
183 {
184 PetscFunctionBegin;
185 d->topology_status = DEOBJECT_INITIALIZED;
186 d->n_neighbour_procs = 0;
187 PetscCall(PetscFree(d->neighbour_procs));
188 PetscCall(PetscFree(d->messages_to_be_sent));
189 PetscCall(PetscFree(d->message_offsets));
190 PetscCall(PetscFree(d->messages_to_be_recvieved));
191 PetscCall(PetscFree(d->pack_cnt));
192 PetscCall(PetscFree(d->send_tags));
193 PetscCall(PetscFree(d->recv_tags));
194 PetscFunctionReturn(PETSC_SUCCESS);
195 }
196
DMSwarmDataExTopologyAddNeighbour(DMSwarmDataEx d,const PetscMPIInt proc_id)197 PetscErrorCode DMSwarmDataExTopologyAddNeighbour(DMSwarmDataEx d, const PetscMPIInt proc_id)
198 {
199 PetscMPIInt n, found;
200 PetscMPIInt size;
201
202 PetscFunctionBegin;
203 PetscCheck(d->topology_status != DEOBJECT_FINALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology has been finalized. To modify or update call DMSwarmDataExTopologyInitialize() first");
204 PetscCheck(d->topology_status == DEOBJECT_INITIALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first");
205
206 /* error on negative entries */
207 PetscCheck(proc_id >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Trying to set proc neighbour with a rank < 0");
208 /* error on ranks larger than number of procs in communicator */
209 PetscCallMPI(MPI_Comm_size(d->comm, &size));
210 PetscCheck(proc_id < size, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Trying to set proc neighbour %d with a rank >= size %d", proc_id, size);
211 if (d->n_neighbour_procs == 0) PetscCall(PetscMalloc1(1, &d->neighbour_procs));
212 /* check for proc_id */
213 found = 0;
214 for (n = 0; n < d->n_neighbour_procs; n++) {
215 if (d->neighbour_procs[n] == proc_id) found = 1;
216 }
217 if (found == 0) { /* add it to list */
218 PetscCall(PetscRealloc(sizeof(PetscMPIInt) * (d->n_neighbour_procs + 1), &d->neighbour_procs));
219 d->neighbour_procs[d->n_neighbour_procs] = proc_id;
220 d->n_neighbour_procs++;
221 }
222 PetscFunctionReturn(PETSC_SUCCESS);
223 }
224
225 /*
226 counter: the index of the communication object
227 N: the number of processors
228 r0: rank of sender
229 r1: rank of receiver
230
231 procs = { 0, 1, 2, 3 }
232
233 0 ==> 0 e=0
234 0 ==> 1 e=1
235 0 ==> 2 e=2
236 0 ==> 3 e=3
237
238 1 ==> 0 e=4
239 1 ==> 1 e=5
240 1 ==> 2 e=6
241 1 ==> 3 e=7
242
243 2 ==> 0 e=8
244 2 ==> 1 e=9
245 2 ==> 2 e=10
246 2 ==> 3 e=11
247
248 3 ==> 0 e=12
249 3 ==> 1 e=13
250 3 ==> 2 e=14
251 3 ==> 3 e=15
252
253 If we require that proc A sends to proc B, then the SEND tag index will be given by
254 N * rank(A) + rank(B) + offset
255 If we require that proc A will receive from proc B, then the RECV tag index will be given by
256 N * rank(B) + rank(A) + offset
257
258 */
_get_tags(PetscInt counter,PetscMPIInt N,PetscMPIInt r0,PetscMPIInt r1,PetscMPIInt maxtag,PetscMPIInt * _st,PetscMPIInt * _rt)259 static void _get_tags(PetscInt counter, PetscMPIInt N, PetscMPIInt r0, PetscMPIInt r1, PetscMPIInt maxtag, PetscMPIInt *_st, PetscMPIInt *_rt)
260 {
261 PetscMPIInt st, rt;
262
263 st = (N * r0 + r1 + N * N * counter) % maxtag;
264 rt = (N * r1 + r0 + N * N * counter) % maxtag;
265 *_st = st;
266 *_rt = rt;
267 }
268
269 /*
270 Makes the communication map symmetric
271 */
DMSwarmDataExCompleteCommunicationMap_Private(MPI_Comm comm,PetscMPIInt n,const PetscMPIInt proc_neighbours[],PetscMPIInt * n_new,PetscMPIInt ** proc_neighbours_new)272 static PetscErrorCode DMSwarmDataExCompleteCommunicationMap_Private(MPI_Comm comm, PetscMPIInt n, const PetscMPIInt proc_neighbours[], PetscMPIInt *n_new, PetscMPIInt **proc_neighbours_new)
273 {
274 Mat A;
275 PetscInt i, j, nc;
276 PetscInt n_, *proc_neighbours_;
277 PetscInt rank_;
278 PetscMPIInt size, rank;
279 PetscScalar *vals;
280 const PetscInt *cols;
281 const PetscScalar *red_vals;
282 PetscMPIInt _n_new, *_proc_neighbours_new;
283
284 PetscFunctionBegin;
285 n_ = n;
286 PetscCall(PetscMalloc1(n_, &proc_neighbours_));
287 for (i = 0; i < n_; ++i) proc_neighbours_[i] = proc_neighbours[i];
288 PetscCallMPI(MPI_Comm_size(comm, &size));
289 PetscCallMPI(MPI_Comm_rank(comm, &rank));
290 rank_ = rank;
291
292 PetscCall(MatCreate(comm, &A));
293 PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, size, size));
294 PetscCall(MatSetType(A, MATAIJ));
295 PetscCall(MatSeqAIJSetPreallocation(A, 1, NULL));
296 PetscCall(MatMPIAIJSetPreallocation(A, n_, NULL, n_, NULL));
297 PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
298 /* Build original map */
299 PetscCall(PetscMalloc1(n_, &vals));
300 for (i = 0; i < n_; ++i) vals[i] = 1.0;
301 PetscCall(MatSetValues(A, 1, &rank_, n_, proc_neighbours_, vals, INSERT_VALUES));
302 PetscCall(MatAssemblyBegin(A, MAT_FLUSH_ASSEMBLY));
303 PetscCall(MatAssemblyEnd(A, MAT_FLUSH_ASSEMBLY));
304 /* Now force all other connections if they are not already there */
305 /* It's more efficient to do them all at once */
306 for (i = 0; i < n_; ++i) vals[i] = 2.0;
307 PetscCall(MatSetValues(A, n_, proc_neighbours_, 1, &rank_, vals, INSERT_VALUES));
308 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
309 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
310 /*
311 PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO));
312 PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD));
313 PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
314 */
315 if ((n_new != NULL) && (proc_neighbours_new != NULL)) {
316 PetscCall(MatGetRow(A, rank_, &nc, &cols, &red_vals));
317 PetscCall(PetscMPIIntCast(nc, &_n_new));
318 PetscCall(PetscMalloc1(_n_new, &_proc_neighbours_new));
319 for (j = 0; j < nc; ++j) PetscCall(PetscMPIIntCast(cols[j], &_proc_neighbours_new[j]));
320 PetscCall(MatRestoreRow(A, rank_, &nc, &cols, &red_vals));
321 *n_new = _n_new;
322 *proc_neighbours_new = _proc_neighbours_new;
323 }
324 PetscCall(MatDestroy(&A));
325 PetscCall(PetscFree(vals));
326 PetscCall(PetscFree(proc_neighbours_));
327 PetscCallMPI(MPI_Barrier(comm));
328 PetscFunctionReturn(PETSC_SUCCESS);
329 }
330
DMSwarmDataExTopologyFinalize(DMSwarmDataEx d)331 PetscErrorCode DMSwarmDataExTopologyFinalize(DMSwarmDataEx d)
332 {
333 PetscMPIInt symm_nn = 0, *symm_procs = NULL, r0, n, st, rt, size, *maxtag, iflg;
334
335 PetscFunctionBegin;
336 PetscCheck(d->topology_status == DEOBJECT_INITIALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first");
337
338 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerTopologySetup, 0, 0, 0, 0));
339 /* given information about all my neighbours, make map symmetric */
340 PetscCall(DMSwarmDataExCompleteCommunicationMap_Private(d->comm, d->n_neighbour_procs, d->neighbour_procs, &symm_nn, &symm_procs));
341 /* update my arrays */
342 PetscCall(PetscFree(d->neighbour_procs));
343 d->n_neighbour_procs = symm_nn;
344 d->neighbour_procs = symm_procs;
345 /* allocates memory */
346 if (!d->messages_to_be_sent) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->messages_to_be_sent));
347 if (!d->message_offsets) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->message_offsets));
348 if (!d->messages_to_be_recvieved) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->messages_to_be_recvieved));
349 if (!d->pack_cnt) PetscCall(PetscMalloc(sizeof(PetscInt) * d->n_neighbour_procs, &d->pack_cnt));
350 if (!d->_stats) PetscCall(PetscMalloc(sizeof(MPI_Status) * 2 * d->n_neighbour_procs, &d->_stats));
351 if (!d->_requests) PetscCall(PetscMalloc(sizeof(MPI_Request) * 2 * d->n_neighbour_procs, &d->_requests));
352 if (!d->send_tags) PetscCall(PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->send_tags));
353 if (!d->recv_tags) PetscCall(PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->recv_tags));
354 /* compute message tags */
355 PetscCallMPI(MPI_Comm_size(d->comm, &size));
356 PetscCallMPI(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &maxtag, &iflg));
357 PetscCheck(iflg, d->comm, PETSC_ERR_LIB, "MPI error: MPI_Comm_get_attr() is not returning a MPI_TAG_UB");
358 r0 = d->rank;
359 for (n = 0; n < d->n_neighbour_procs; ++n) {
360 PetscMPIInt r1 = d->neighbour_procs[n];
361
362 _get_tags(d->instance, size, r0, r1, *maxtag, &st, &rt);
363 d->send_tags[n] = st;
364 d->recv_tags[n] = rt;
365 }
366 d->topology_status = DEOBJECT_FINALIZED;
367 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerTopologySetup, 0, 0, 0, 0));
368 PetscFunctionReturn(PETSC_SUCCESS);
369 }
370
371 /* === Phase B === */
_DMSwarmDataExConvertProcIdToLocalIndex(DMSwarmDataEx de,PetscMPIInt proc_id,PetscMPIInt * local)372 static PetscErrorCode _DMSwarmDataExConvertProcIdToLocalIndex(DMSwarmDataEx de, PetscMPIInt proc_id, PetscMPIInt *local)
373 {
374 PetscMPIInt i, np;
375
376 PetscFunctionBegin;
377 np = de->n_neighbour_procs;
378 *local = -1;
379 for (i = 0; i < np; ++i) {
380 if (proc_id == de->neighbour_procs[i]) {
381 *local = i;
382 break;
383 }
384 }
385 PetscFunctionReturn(PETSC_SUCCESS);
386 }
387
DMSwarmDataExInitializeSendCount(DMSwarmDataEx de)388 PetscErrorCode DMSwarmDataExInitializeSendCount(DMSwarmDataEx de)
389 {
390 PetscMPIInt i;
391
392 PetscFunctionBegin;
393 PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized");
394 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerSendCount, 0, 0, 0, 0));
395 de->message_lengths_status = DEOBJECT_INITIALIZED;
396 for (i = 0; i < de->n_neighbour_procs; ++i) de->messages_to_be_sent[i] = 0;
397 PetscFunctionReturn(PETSC_SUCCESS);
398 }
399
400 /*
401 1) only allows counters to be set on neighbouring cpus
402 */
DMSwarmDataExAddToSendCount(DMSwarmDataEx de,const PetscMPIInt proc_id,const PetscInt count)403 PetscErrorCode DMSwarmDataExAddToSendCount(DMSwarmDataEx de, const PetscMPIInt proc_id, const PetscInt count)
404 {
405 PetscMPIInt local_val;
406
407 PetscFunctionBegin;
408 PetscCheck(de->message_lengths_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths have been defined. To modify these call DMSwarmDataExInitializeSendCount() first");
409 PetscCheck(de->message_lengths_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first");
410
411 PetscCall(_DMSwarmDataExConvertProcIdToLocalIndex(de, proc_id, &local_val));
412 PetscCheck(local_val != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Proc %d is not a valid neighbour rank", (int)proc_id);
413
414 de->messages_to_be_sent[local_val] = de->messages_to_be_sent[local_val] + count;
415 PetscFunctionReturn(PETSC_SUCCESS);
416 }
417
DMSwarmDataExFinalizeSendCount(DMSwarmDataEx de)418 PetscErrorCode DMSwarmDataExFinalizeSendCount(DMSwarmDataEx de)
419 {
420 PetscFunctionBegin;
421 PetscCheck(de->message_lengths_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first");
422
423 de->message_lengths_status = DEOBJECT_FINALIZED;
424 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerSendCount, 0, 0, 0, 0));
425 PetscFunctionReturn(PETSC_SUCCESS);
426 }
427
428 /* === Phase C === */
429 /*
430 zero out all send counts
431 free send and recv buffers
432 zeros out message length
433 zeros out all counters
434 zero out packed data counters
435 */
_DMSwarmDataExInitializeTmpStorage(DMSwarmDataEx de)436 static PetscErrorCode _DMSwarmDataExInitializeTmpStorage(DMSwarmDataEx de)
437 {
438 PetscMPIInt i, np;
439
440 PetscFunctionBegin;
441 np = de->n_neighbour_procs;
442 for (i = 0; i < np; ++i) {
443 /* de->messages_to_be_sent[i] = -1; */
444 de->messages_to_be_recvieved[i] = -1;
445 }
446 PetscCall(PetscFree(de->send_message));
447 PetscCall(PetscFree(de->recv_message));
448 PetscFunctionReturn(PETSC_SUCCESS);
449 }
450
451 /*
452 Zeros out pack data counters
453 Ensures mesaage length is set
454 Checks send counts properly initialized
455 allocates space for pack data
456 */
DMSwarmDataExPackInitialize(DMSwarmDataEx de,size_t unit_message_size)457 PetscErrorCode DMSwarmDataExPackInitialize(DMSwarmDataEx de, size_t unit_message_size)
458 {
459 PetscMPIInt i, np;
460 PetscInt total;
461
462 PetscFunctionBegin;
463 PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized");
464 PetscCheck(de->message_lengths_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths not finalized");
465 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerPack, 0, 0, 0, 0));
466 de->packer_status = DEOBJECT_INITIALIZED;
467 PetscCall(_DMSwarmDataExInitializeTmpStorage(de));
468 np = de->n_neighbour_procs;
469 de->unit_message_size = unit_message_size;
470 total = 0;
471 for (i = 0; i < np; ++i) {
472 if (de->messages_to_be_sent[i] == -1) {
473 PetscMPIInt proc_neighour = de->neighbour_procs[i];
474 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ORDER, "Messages_to_be_sent[neighbour_proc=%d] is un-initialised. Call DMSwarmDataExSetSendCount() first", proc_neighour);
475 }
476 total = total + de->messages_to_be_sent[i];
477 }
478 /* create space for the data to be sent */
479 PetscCall(PetscMalloc(unit_message_size * (total + 1), &de->send_message));
480 /* initialize memory */
481 PetscCall(PetscMemzero(de->send_message, unit_message_size * (total + 1)));
482 /* set total items to send */
483 de->send_message_length = total;
484 de->message_offsets[0] = 0;
485 total = de->messages_to_be_sent[0];
486 for (i = 1; i < np; ++i) {
487 de->message_offsets[i] = total;
488 total = total + de->messages_to_be_sent[i];
489 }
490 /* init the packer counters */
491 de->total_pack_cnt = 0;
492 for (i = 0; i < np; ++i) de->pack_cnt[i] = 0;
493 PetscFunctionReturn(PETSC_SUCCESS);
494 }
495
496 /*
497 Ensures data gets been packed appropriately and no overlaps occur
498 */
DMSwarmDataExPackData(DMSwarmDataEx de,PetscMPIInt proc_id,PetscInt n,void * data)499 PetscErrorCode DMSwarmDataExPackData(DMSwarmDataEx de, PetscMPIInt proc_id, PetscInt n, void *data)
500 {
501 PetscMPIInt local;
502 PetscInt insert_location;
503 void *dest;
504
505 PetscFunctionBegin;
506 PetscCheck(de->packer_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Packed data have been defined. To modify these call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first");
507 PetscCheck(de->packer_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Packed data must be defined. Call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first");
508
509 PetscCheck(de->send_message, de->comm, PETSC_ERR_ORDER, "send_message is not initialized. Call DMSwarmDataExPackInitialize() first");
510 PetscCall(_DMSwarmDataExConvertProcIdToLocalIndex(de, proc_id, &local));
511 PetscCheck(local != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "proc_id %d is not registered neighbour", proc_id);
512 PetscCheck(n + de->pack_cnt[local] <= de->messages_to_be_sent[local], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to pack too many entries to be sent to proc %d. Space requested = %" PetscInt_FMT ": Attempt to insert %" PetscInt_FMT, proc_id, de->messages_to_be_sent[local], n + de->pack_cnt[local]);
513
514 /* copy memory */
515 insert_location = de->message_offsets[local] + de->pack_cnt[local];
516 dest = ((char *)de->send_message) + de->unit_message_size * insert_location;
517 PetscCall(PetscMemcpy(dest, data, de->unit_message_size * n));
518 /* increment counter */
519 de->pack_cnt[local] = de->pack_cnt[local] + n;
520 PetscFunctionReturn(PETSC_SUCCESS);
521 }
522
523 /*
524 *) Ensures all data has been packed
525 */
DMSwarmDataExPackFinalize(DMSwarmDataEx de)526 PetscErrorCode DMSwarmDataExPackFinalize(DMSwarmDataEx de)
527 {
528 PetscMPIInt i, np;
529 PetscInt total;
530
531 PetscFunctionBegin;
532 PetscCheck(de->packer_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Packer has not been initialized. Must call DMSwarmDataExPackInitialize() first.");
533 np = de->n_neighbour_procs;
534 for (i = 0; i < np; ++i) {
535 PetscCheck(de->pack_cnt[i] == de->messages_to_be_sent[i], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not all messages for neighbour[%d] have been packed. Expected %" PetscInt_FMT " : Inserted %" PetscInt_FMT, de->neighbour_procs[i], de->messages_to_be_sent[i], de->pack_cnt[i]);
536 }
537 /* init */
538 for (i = 0; i < np; ++i) de->messages_to_be_recvieved[i] = -1;
539 /* figure out the recv counts here */
540 for (i = 0; i < np; ++i) PetscCallMPI(MPIU_Isend(&de->messages_to_be_sent[i], 1, MPIU_INT, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]));
541 for (i = 0; i < np; ++i) PetscCallMPI(MPIU_Irecv(&de->messages_to_be_recvieved[i], 1, MPIU_INT, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np + i]));
542 PetscCallMPI(MPI_Waitall(2 * np, de->_requests, de->_stats));
543 /* create space for the data to be recvieved */
544 total = 0;
545 for (i = 0; i < np; ++i) total = total + de->messages_to_be_recvieved[i];
546 PetscCall(PetscMalloc(de->unit_message_size * (total + 1), &de->recv_message));
547 /* initialize memory */
548 PetscCall(PetscMemzero(de->recv_message, de->unit_message_size * (total + 1)));
549 /* set total items to receive */
550 de->recv_message_length = total;
551 de->packer_status = DEOBJECT_FINALIZED;
552 de->communication_status = DEOBJECT_INITIALIZED;
553 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerPack, 0, 0, 0, 0));
554 PetscFunctionReturn(PETSC_SUCCESS);
555 }
556
557 /* do the actual message passing */
DMSwarmDataExBegin(DMSwarmDataEx de)558 PetscErrorCode DMSwarmDataExBegin(DMSwarmDataEx de)
559 {
560 PetscMPIInt i, np;
561 void *dest;
562
563 PetscFunctionBegin;
564 PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized");
565 PetscCheck(de->message_lengths_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths not finalized");
566 PetscCheck(de->packer_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Packer not finalized");
567 PetscCheck(de->communication_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Communication has already been finalized. Must call DMSwarmDataExInitialize() first.");
568 PetscCheck(de->recv_message, de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first");
569 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerBegin, 0, 0, 0, 0));
570 np = de->n_neighbour_procs;
571 /* == NON BLOCKING == */
572 for (i = 0; i < np; ++i) {
573 dest = ((char *)de->send_message) + de->unit_message_size * de->message_offsets[i];
574 PetscCallMPI(MPIU_Isend(dest, de->messages_to_be_sent[i] * de->unit_message_size, MPI_CHAR, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]));
575 }
576 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerBegin, 0, 0, 0, 0));
577 PetscFunctionReturn(PETSC_SUCCESS);
578 }
579
580 /* do the actual message passing now */
DMSwarmDataExEnd(DMSwarmDataEx de)581 PetscErrorCode DMSwarmDataExEnd(DMSwarmDataEx de)
582 {
583 PetscMPIInt i, np;
584 PetscInt total;
585 PetscInt *message_recv_offsets;
586 void *dest;
587
588 PetscFunctionBegin;
589 PetscCheck(de->communication_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Communication has not been initialized. Must call DMSwarmDataExInitialize() first.");
590 PetscCheck(de->recv_message, de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first");
591 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerEnd, 0, 0, 0, 0));
592 np = de->n_neighbour_procs;
593 PetscCall(PetscMalloc1(np + 1, &message_recv_offsets));
594 message_recv_offsets[0] = 0;
595 total = de->messages_to_be_recvieved[0];
596 for (i = 1; i < np; ++i) {
597 message_recv_offsets[i] = total;
598 total = total + de->messages_to_be_recvieved[i];
599 }
600 /* == NON BLOCKING == */
601 for (i = 0; i < np; ++i) {
602 dest = ((char *)de->recv_message) + de->unit_message_size * message_recv_offsets[i];
603 PetscCallMPI(MPIU_Irecv(dest, de->messages_to_be_recvieved[i] * de->unit_message_size, MPI_CHAR, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np + i]));
604 }
605 PetscCallMPI(MPI_Waitall(2 * np, de->_requests, de->_stats));
606 PetscCall(PetscFree(message_recv_offsets));
607 de->communication_status = DEOBJECT_FINALIZED;
608 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerEnd, 0, 0, 0, 0));
609 PetscFunctionReturn(PETSC_SUCCESS);
610 }
611
DMSwarmDataExGetSendData(DMSwarmDataEx de,PetscInt * length,void ** send)612 PetscErrorCode DMSwarmDataExGetSendData(DMSwarmDataEx de, PetscInt *length, void **send)
613 {
614 PetscFunctionBegin;
615 PetscCheck(de->packer_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being packed.");
616 *length = de->send_message_length;
617 *send = de->send_message;
618 PetscFunctionReturn(PETSC_SUCCESS);
619 }
620
DMSwarmDataExGetRecvData(DMSwarmDataEx de,PetscInt * length,void ** recv)621 PetscErrorCode DMSwarmDataExGetRecvData(DMSwarmDataEx de, PetscInt *length, void **recv)
622 {
623 PetscFunctionBegin;
624 PetscCheck(de->communication_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being sent.");
625 *length = de->recv_message_length;
626 *recv = de->recv_message;
627 PetscFunctionReturn(PETSC_SUCCESS);
628 }
629
DMSwarmDataExTopologyGetNeighbours(DMSwarmDataEx de,PetscMPIInt * n,PetscMPIInt * neigh[])630 PetscErrorCode DMSwarmDataExTopologyGetNeighbours(DMSwarmDataEx de, PetscMPIInt *n, PetscMPIInt *neigh[])
631 {
632 PetscFunctionBegin;
633 if (n) *n = de->n_neighbour_procs;
634 if (neigh) *neigh = de->neighbour_procs;
635 PetscFunctionReturn(PETSC_SUCCESS);
636 }
637