Actual source code: data_ex.c
1: /*
2: Build a few basic tools to help with partitioned domains.
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 identifers.
10: edge
11: 10
12: proc ---------> proc
13: 0 <-------- 1
14: 11
15: twin
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
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.
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
31: data to 0 data to 2 data to 3
33: |--------|-----------------|--|
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.
38: Phase A: Build topology
40: Phase B: Define message lengths
42: Phase C: Pack data
44: Phase D: Send data
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()
68: ... user calls any getters here ...
70: */
71: #include <petscvec.h>
72: #include <petscmat.h>
74: #include "../src/dm/impls/swarm/data_ex.h"
76: const char *status_names[] = {"initialized", "finalized", "unknown"};
78: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerTopologySetup;
79: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerBegin;
80: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerEnd;
81: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerSendCount;
82: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerPack;
84: PetscErrorCode DMSwarmDataExCreate(MPI_Comm comm,const PetscInt count, DMSwarmDataEx *ex)
85: {
87: DMSwarmDataEx d;
90: PetscMalloc(sizeof(struct _p_DMSwarmDataEx), &d);
91: PetscMemzero(d, sizeof(struct _p_DMSwarmDataEx));
92: MPI_Comm_dup(comm,&d->comm);
93: MPI_Comm_rank(d->comm,&d->rank);
95: d->instance = count;
97: d->topology_status = DEOBJECT_STATE_UNKNOWN;
98: d->message_lengths_status = DEOBJECT_STATE_UNKNOWN;
99: d->packer_status = DEOBJECT_STATE_UNKNOWN;
100: d->communication_status = DEOBJECT_STATE_UNKNOWN;
102: d->n_neighbour_procs = -1;
103: d->neighbour_procs = NULL;
105: d->messages_to_be_sent = NULL;
106: d->message_offsets = NULL;
107: d->messages_to_be_recvieved = NULL;
109: d->unit_message_size = (size_t)-1;
110: d->send_message = NULL;
111: d->send_message_length = -1;
112: d->recv_message = NULL;
113: d->recv_message_length = -1;
114: d->total_pack_cnt = -1;
115: d->pack_cnt = NULL;
117: d->send_tags = NULL;
118: d->recv_tags = NULL;
120: d->_stats = NULL;
121: d->_requests = NULL;
122: *ex = d;
123: return(0);
124: }
126: /*
127: This code is horrible, who let it get into main.
129: Should be printing to a viewer, should not be using PETSC_COMM_WORLD
131: */
132: PetscErrorCode DMSwarmDataExView(DMSwarmDataEx d)
133: {
134: PetscMPIInt p;
138: PetscPrintf( PETSC_COMM_WORLD, "DMSwarmDataEx: instance=%D\n",d->instance);
139: PetscPrintf( PETSC_COMM_WORLD, " topology status: %s \n", status_names[d->topology_status]);
140: PetscPrintf( PETSC_COMM_WORLD, " message lengths status: %s \n", status_names[d->message_lengths_status]);
141: PetscPrintf( PETSC_COMM_WORLD, " packer status status: %s \n", status_names[d->packer_status]);
142: PetscPrintf( PETSC_COMM_WORLD, " communication status: %s \n", status_names[d->communication_status]);
144: if (d->topology_status == DEOBJECT_FINALIZED) {
145: PetscPrintf( PETSC_COMM_WORLD, " Topology:\n");
146: PetscSynchronizedPrintf( PETSC_COMM_WORLD, " [%d] neighbours: %d \n", d->rank, d->n_neighbour_procs);
147: for (p=0; p<d->n_neighbour_procs; p++) {
148: PetscSynchronizedPrintf( PETSC_COMM_WORLD, " [%d] neighbour[%d] = %d \n", d->rank, p, d->neighbour_procs[p]);
149: }
150: PetscSynchronizedFlush(PETSC_COMM_WORLD,stdout);
151: }
153: if (d->message_lengths_status == DEOBJECT_FINALIZED) {
154: PetscPrintf( PETSC_COMM_WORLD, " Message lengths:\n");
155: PetscSynchronizedPrintf( PETSC_COMM_WORLD, " [%d] atomic size: %ld \n", d->rank, (long int)d->unit_message_size);
156: for (p=0; p<d->n_neighbour_procs; p++) {
157: PetscSynchronizedPrintf( PETSC_COMM_WORLD, " [%d] >>>>> ( %D units :: tag = %d) >>>>> [%d] \n", d->rank, d->messages_to_be_sent[p], d->send_tags[p], d->neighbour_procs[p]);
158: }
159: for (p=0; p<d->n_neighbour_procs; p++) {
160: PetscSynchronizedPrintf( PETSC_COMM_WORLD, " [%d] <<<<< ( %D units :: tag = %d) <<<<< [%d] \n", d->rank, d->messages_to_be_recvieved[p], d->recv_tags[p], d->neighbour_procs[p]);
161: }
162: PetscSynchronizedFlush(PETSC_COMM_WORLD,stdout);
163: }
164: if (d->packer_status == DEOBJECT_FINALIZED) {}
165: if (d->communication_status == DEOBJECT_FINALIZED) {}
166: return(0);
167: }
169: PetscErrorCode DMSwarmDataExDestroy(DMSwarmDataEx d)
170: {
174: MPI_Comm_free(&d->comm);
175: if (d->neighbour_procs) {PetscFree(d->neighbour_procs);}
176: if (d->messages_to_be_sent) {PetscFree(d->messages_to_be_sent);}
177: if (d->message_offsets) {PetscFree(d->message_offsets);}
178: if (d->messages_to_be_recvieved) {PetscFree(d->messages_to_be_recvieved);}
179: if (d->send_message) {PetscFree(d->send_message);}
180: if (d->recv_message) {PetscFree(d->recv_message);}
181: if (d->pack_cnt) {PetscFree(d->pack_cnt);}
182: if (d->send_tags) {PetscFree(d->send_tags);}
183: if (d->recv_tags) {PetscFree(d->recv_tags);}
184: if (d->_stats) {PetscFree(d->_stats);}
185: if (d->_requests) {PetscFree(d->_requests);}
186: PetscFree(d);
187: return(0);
188: }
190: /* === Phase A === */
192: PetscErrorCode DMSwarmDataExTopologyInitialize(DMSwarmDataEx d)
193: {
197: d->topology_status = DEOBJECT_INITIALIZED;
198: d->n_neighbour_procs = 0;
199: PetscFree(d->neighbour_procs);
200: PetscFree(d->messages_to_be_sent);
201: PetscFree(d->message_offsets);
202: PetscFree(d->messages_to_be_recvieved);
203: PetscFree(d->pack_cnt);
204: PetscFree(d->send_tags);
205: PetscFree(d->recv_tags);
206: return(0);
207: }
209: PetscErrorCode DMSwarmDataExTopologyAddNeighbour(DMSwarmDataEx d,const PetscMPIInt proc_id)
210: {
211: PetscMPIInt n,found;
212: PetscMPIInt size;
216: if (d->topology_status == DEOBJECT_FINALIZED) SETERRQ(d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology has been finalized. To modify or update call DMSwarmDataExTopologyInitialize() first");
217: else if (d->topology_status != DEOBJECT_INITIALIZED) SETERRQ(d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first");
219: /* error on negative entries */
220: if (proc_id < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Trying to set proc neighbour with a rank < 0");
221: /* error on ranks larger than number of procs in communicator */
222: MPI_Comm_size(d->comm,&size);
223: if (proc_id >= size) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Trying to set proc neighbour %d with a rank >= size %d",proc_id,size);
224: if (d->n_neighbour_procs == 0) {PetscMalloc1(1, &d->neighbour_procs);}
225: /* check for proc_id */
226: found = 0;
227: for (n = 0; n < d->n_neighbour_procs; n++) {
228: if (d->neighbour_procs[n] == proc_id) {
229: found = 1;
230: }
231: }
232: if (found == 0) { /* add it to list */
233: PetscRealloc(sizeof(PetscMPIInt)*(d->n_neighbour_procs+1), &d->neighbour_procs);
234: d->neighbour_procs[ d->n_neighbour_procs ] = proc_id;
235: d->n_neighbour_procs++;
236: }
237: return(0);
238: }
240: /*
241: counter: the index of the communication object
242: N: the number of processors
243: r0: rank of sender
244: r1: rank of receiver
246: procs = { 0, 1, 2, 3 }
248: 0 ==> 0 e=0
249: 0 ==> 1 e=1
250: 0 ==> 2 e=2
251: 0 ==> 3 e=3
253: 1 ==> 0 e=4
254: 1 ==> 1 e=5
255: 1 ==> 2 e=6
256: 1 ==> 3 e=7
258: 2 ==> 0 e=8
259: 2 ==> 1 e=9
260: 2 ==> 2 e=10
261: 2 ==> 3 e=11
263: 3 ==> 0 e=12
264: 3 ==> 1 e=13
265: 3 ==> 2 e=14
266: 3 ==> 3 e=15
268: If we require that proc A sends to proc B, then the SEND tag index will be given by
269: N * rank(A) + rank(B) + offset
270: If we require that proc A will receive from proc B, then the RECV tag index will be given by
271: N * rank(B) + rank(A) + offset
273: */
274: static void _get_tags(PetscInt counter, PetscMPIInt N, PetscMPIInt r0,PetscMPIInt r1, PetscMPIInt *_st, PetscMPIInt *_rt)
275: {
276: PetscMPIInt st,rt;
278: st = N*r0 + r1 + N*N*counter;
279: rt = N*r1 + r0 + N*N*counter;
280: *_st = st;
281: *_rt = rt;
282: }
284: /*
285: Makes the communication map symmetric
286: */
287: PetscErrorCode _DMSwarmDataExCompleteCommunicationMap(MPI_Comm comm,PetscMPIInt n,PetscMPIInt proc_neighbours[],PetscMPIInt *n_new,PetscMPIInt **proc_neighbours_new)
288: {
289: Mat A;
290: PetscInt i,j,nc;
291: PetscInt n_, *proc_neighbours_;
292: PetscInt rank_;
293: PetscMPIInt size, rank;
294: PetscScalar *vals;
295: const PetscInt *cols;
296: const PetscScalar *red_vals;
297: PetscMPIInt _n_new, *_proc_neighbours_new;
298: PetscErrorCode ierr;
301: n_ = n;
302: PetscMalloc(sizeof(PetscInt) * n_, &proc_neighbours_);
303: for (i = 0; i < n_; ++i) {
304: proc_neighbours_[i] = proc_neighbours[i];
305: }
306: MPI_Comm_size(comm,&size);
307: MPI_Comm_rank(comm,&rank);
308: rank_ = rank;
310: MatCreate(comm,&A);
311: MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,size,size);
312: MatSetType(A,MATAIJ);
313: MatSeqAIJSetPreallocation(A,1,NULL);
314: MatMPIAIJSetPreallocation(A,n_,NULL,n_,NULL);
315: MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
316: /* Build original map */
317: PetscMalloc1(n_, &vals);
318: for (i = 0; i < n_; ++i) {
319: vals[i] = 1.0;
320: }
321: MatSetValues( A, 1,&rank_, n_,proc_neighbours_, vals, INSERT_VALUES);
322: MatAssemblyBegin(A,MAT_FLUSH_ASSEMBLY);
323: MatAssemblyEnd(A,MAT_FLUSH_ASSEMBLY);
324: /* Now force all other connections if they are not already there */
325: /* It's more efficient to do them all at once */
326: for (i = 0; i < n_; ++i) {
327: vals[i] = 2.0;
328: }
329: MatSetValues( A, n_,proc_neighbours_, 1,&rank_, vals, INSERT_VALUES);
330: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
331: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
332: /*
333: PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO);
334: MatView(A,PETSC_VIEWER_STDOUT_WORLD);
335: PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);
336: */
337: if ((n_new != NULL) && (proc_neighbours_new != NULL)) {
338: MatGetRow(A, rank_, &nc, &cols, &red_vals);
339: _n_new = (PetscMPIInt) nc;
340: PetscMalloc1(_n_new, &_proc_neighbours_new);
341: for (j = 0; j < nc; ++j) {
342: _proc_neighbours_new[j] = (PetscMPIInt)cols[j];
343: }
344: MatRestoreRow( A, rank_, &nc, &cols, &red_vals);
345: *n_new = (PetscMPIInt)_n_new;
346: *proc_neighbours_new = (PetscMPIInt*)_proc_neighbours_new;
347: }
348: MatDestroy(&A);
349: PetscFree(vals);
350: PetscFree(proc_neighbours_);
351: MPI_Barrier(comm);
352: return(0);
353: }
355: PetscErrorCode DMSwarmDataExTopologyFinalize(DMSwarmDataEx d)
356: {
357: PetscMPIInt symm_nn;
358: PetscMPIInt *symm_procs;
359: PetscMPIInt r0,n,st,rt;
360: PetscMPIInt size;
364: if (d->topology_status != DEOBJECT_INITIALIZED) SETERRQ(d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first");
366: PetscLogEventBegin(DMSWARM_DataExchangerTopologySetup,0,0,0,0);
367: /* given information about all my neighbours, make map symmetric */
368: _DMSwarmDataExCompleteCommunicationMap( d->comm,d->n_neighbour_procs,d->neighbour_procs, &symm_nn, &symm_procs);
369: /* update my arrays */
370: PetscFree(d->neighbour_procs);
371: d->n_neighbour_procs = symm_nn;
372: d->neighbour_procs = symm_procs;
373: /* allocates memory */
374: if (!d->messages_to_be_sent) {PetscMalloc1(d->n_neighbour_procs+1, &d->messages_to_be_sent);}
375: if (!d->message_offsets) {PetscMalloc1(d->n_neighbour_procs+1, &d->message_offsets);}
376: if (!d->messages_to_be_recvieved) {PetscMalloc1(d->n_neighbour_procs+1, &d->messages_to_be_recvieved);}
377: if (!d->pack_cnt) {PetscMalloc(sizeof(PetscInt) * d->n_neighbour_procs, &d->pack_cnt);}
378: if (!d->_stats) {PetscMalloc(sizeof(MPI_Status) * 2*d->n_neighbour_procs, &d->_stats);}
379: if (!d->_requests) {PetscMalloc(sizeof(MPI_Request) * 2*d->n_neighbour_procs, &d->_requests);}
380: if (!d->send_tags) {PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->send_tags);}
381: if (!d->recv_tags) {PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->recv_tags);}
382: /* compute message tags */
383: MPI_Comm_size(d->comm,&size);
384: r0 = d->rank;
385: for (n = 0; n < d->n_neighbour_procs; ++n) {
386: PetscMPIInt r1 = d->neighbour_procs[n];
388: _get_tags( d->instance, size, r0,r1, &st, &rt);
389: d->send_tags[n] = (int)st;
390: d->recv_tags[n] = (int)rt;
391: }
392: d->topology_status = DEOBJECT_FINALIZED;
393: PetscLogEventEnd(DMSWARM_DataExchangerTopologySetup,0,0,0,0);
394: return(0);
395: }
397: /* === Phase B === */
398: PetscErrorCode _DMSwarmDataExConvertProcIdToLocalIndex(DMSwarmDataEx de,PetscMPIInt proc_id,PetscMPIInt *local)
399: {
400: PetscMPIInt i,np;
403: np = de->n_neighbour_procs;
404: *local = -1;
405: for (i = 0; i < np; ++i) {
406: if (proc_id == de->neighbour_procs[i]) {
407: *local = i;
408: break;
409: }
410: }
411: return(0);
412: }
414: PetscErrorCode DMSwarmDataExInitializeSendCount(DMSwarmDataEx de)
415: {
416: PetscMPIInt i;
420: if (de->topology_status != DEOBJECT_FINALIZED) SETERRQ(de->comm, PETSC_ERR_ORDER, "Topology not finalized");
421: PetscLogEventBegin(DMSWARM_DataExchangerSendCount,0,0,0,0);
422: de->message_lengths_status = DEOBJECT_INITIALIZED;
423: for (i = 0; i < de->n_neighbour_procs; ++i) {
424: de->messages_to_be_sent[i] = 0;
425: }
426: return(0);
427: }
429: /*
430: 1) only allows counters to be set on neighbouring cpus
431: */
432: PetscErrorCode DMSwarmDataExAddToSendCount(DMSwarmDataEx de,const PetscMPIInt proc_id,const PetscInt count)
433: {
434: PetscMPIInt local_val;
438: if (de->message_lengths_status == DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths have been defined. To modify these call DMSwarmDataExInitializeSendCount() first");
439: else if (de->message_lengths_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first");
441: _DMSwarmDataExConvertProcIdToLocalIndex( de, proc_id, &local_val);
442: if (local_val == -1) SETERRQ1( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,"Proc %d is not a valid neighbour rank", (int)proc_id);
444: de->messages_to_be_sent[local_val] = de->messages_to_be_sent[local_val] + count;
445: return(0);
446: }
448: PetscErrorCode DMSwarmDataExFinalizeSendCount(DMSwarmDataEx de)
449: {
453: if (de->message_lengths_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first");
455: de->message_lengths_status = DEOBJECT_FINALIZED;
456: PetscLogEventEnd(DMSWARM_DataExchangerSendCount,0,0,0,0);
457: return(0);
458: }
460: /* === Phase C === */
461: /*
462: * zero out all send counts
463: * free send and recv buffers
464: * zeros out message length
465: * zeros out all counters
466: * zero out packed data counters
467: */
468: PetscErrorCode _DMSwarmDataExInitializeTmpStorage(DMSwarmDataEx de)
469: {
470: PetscMPIInt i, np;
474: /*if (de->n_neighbour_procs < 0) SETERRQ( PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of neighbour procs < 0");
475: */
476: /*
477: if (!de->neighbour_procs) SETERRQ( PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Neighbour proc list is NULL");
478: */
479: np = de->n_neighbour_procs;
480: for (i = 0; i < np; ++i) {
481: /* de->messages_to_be_sent[i] = -1; */
482: de->messages_to_be_recvieved[i] = -1;
483: }
484: PetscFree(de->send_message);
485: PetscFree(de->recv_message);
486: return(0);
487: }
489: /*
490: *) Zeros out pack data counters
491: *) Ensures mesaage length is set
492: *) Checks send counts properly initialized
493: *) allocates space for pack data
494: */
495: PetscErrorCode DMSwarmDataExPackInitialize(DMSwarmDataEx de,size_t unit_message_size)
496: {
497: PetscMPIInt i,np;
498: PetscInt total;
502: if (de->topology_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Topology not finalized");
503: if (de->message_lengths_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths not finalized");
504: PetscLogEventBegin(DMSWARM_DataExchangerPack,0,0,0,0);
505: de->packer_status = DEOBJECT_INITIALIZED;
506: _DMSwarmDataExInitializeTmpStorage(de);
507: np = de->n_neighbour_procs;
508: de->unit_message_size = unit_message_size;
509: total = 0;
510: for (i = 0; i < np; ++i) {
511: if (de->messages_to_be_sent[i] == -1) {
512: PetscMPIInt proc_neighour = de->neighbour_procs[i];
513: SETERRQ1( PETSC_COMM_SELF, PETSC_ERR_ORDER, "Messages_to_be_sent[neighbour_proc=%d] is un-initialised. Call DMSwarmDataExSetSendCount() first", (int)proc_neighour);
514: }
515: total = total + de->messages_to_be_sent[i];
516: }
517: /* create space for the data to be sent */
518: PetscMalloc(unit_message_size * (total + 1), &de->send_message);
519: /* initialize memory */
520: PetscMemzero(de->send_message, unit_message_size * (total + 1));
521: /* set total items to send */
522: de->send_message_length = total;
523: de->message_offsets[0] = 0;
524: total = de->messages_to_be_sent[0];
525: for (i = 1; i < np; ++i) {
526: de->message_offsets[i] = total;
527: total = total + de->messages_to_be_sent[i];
528: }
529: /* init the packer counters */
530: de->total_pack_cnt = 0;
531: for (i = 0; i < np; ++i) {
532: de->pack_cnt[i] = 0;
533: }
534: return(0);
535: }
537: /*
538: *) Ensures data gets been packed appropriately and no overlaps occur
539: */
540: PetscErrorCode DMSwarmDataExPackData(DMSwarmDataEx de,PetscMPIInt proc_id,PetscInt n,void *data)
541: {
542: PetscMPIInt local;
543: PetscInt insert_location;
544: void *dest;
548: if (de->packer_status == DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packed data have been defined. To modify these call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first");
549: else if (de->packer_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packed data must be defined. Call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first");
551: if (!de->send_message) SETERRQ( de->comm, PETSC_ERR_ORDER, "send_message is not initialized. Call DMSwarmDataExPackInitialize() first");
552: _DMSwarmDataExConvertProcIdToLocalIndex( de, proc_id, &local);
553: if (local == -1) SETERRQ1( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "proc_id %d is not registered neighbour", (int)proc_id);
554: if (n+de->pack_cnt[local] > de->messages_to_be_sent[local]) SETERRQ3( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to pack too many entries to be sent to proc %d. Space requested = %D: Attempt to insert %D",
555: (int)proc_id, de->messages_to_be_sent[local], n+de->pack_cnt[local]);
557: /* copy memory */
558: insert_location = de->message_offsets[local] + de->pack_cnt[local];
559: dest = ((char*)de->send_message) + de->unit_message_size*insert_location;
560: PetscMemcpy(dest, data, de->unit_message_size * n);
561: /* increment counter */
562: de->pack_cnt[local] = de->pack_cnt[local] + n;
563: return(0);
564: }
566: /*
567: *) Ensures all data has been packed
568: */
569: PetscErrorCode DMSwarmDataExPackFinalize(DMSwarmDataEx de)
570: {
571: PetscMPIInt i,np;
572: PetscInt total;
576: if (de->packer_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packer has not been initialized. Must call DMSwarmDataExPackInitialize() first.");
577: np = de->n_neighbour_procs;
578: for (i = 0; i < np; ++i) {
579: if (de->pack_cnt[i] != de->messages_to_be_sent[i]) SETERRQ3( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not all messages for neighbour[%d] have been packed. Expected %D : Inserted %D",
580: (int)de->neighbour_procs[i], de->messages_to_be_sent[i], de->pack_cnt[i]);
581: }
582: /* init */
583: for (i = 0; i < np; ++i) {
584: de->messages_to_be_recvieved[i] = -1;
585: }
586: /* figure out the recv counts here */
587: for (i = 0; i < np; ++i) {
588: MPI_Isend(&de->messages_to_be_sent[i], 1, MPIU_INT, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]);
589: }
590: for (i = 0; i < np; ++i) {
591: MPI_Irecv(&de->messages_to_be_recvieved[i], 1, MPIU_INT, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np+i]);
592: }
593: MPI_Waitall(2*np, de->_requests, de->_stats);
594: /* create space for the data to be recvieved */
595: total = 0;
596: for (i = 0; i < np; ++i) {
597: total = total + de->messages_to_be_recvieved[i];
598: }
599: PetscMalloc(de->unit_message_size * (total + 1), &de->recv_message);
600: /* initialize memory */
601: PetscMemzero(de->recv_message, de->unit_message_size * (total + 1));
602: /* set total items to receive */
603: de->recv_message_length = total;
604: de->packer_status = DEOBJECT_FINALIZED;
605: de->communication_status = DEOBJECT_INITIALIZED;
606: PetscLogEventEnd(DMSWARM_DataExchangerPack,0,0,0,0);
607: return(0);
608: }
610: /* do the actual message passing now */
611: PetscErrorCode DMSwarmDataExBegin(DMSwarmDataEx de)
612: {
613: PetscMPIInt i,np;
614: void *dest;
615: PetscInt length;
619: if (de->topology_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Topology not finalized");
620: if (de->message_lengths_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths not finalized");
621: if (de->packer_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packer not finalized");
622: if (de->communication_status == DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Communication has already been finalized. Must call DMSwarmDataExInitialize() first.");
623: if (!de->recv_message) SETERRQ( de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first");
624: PetscLogEventBegin(DMSWARM_DataExchangerBegin,0,0,0,0);
625: np = de->n_neighbour_procs;
626: /* == NON BLOCKING == */
627: for (i = 0; i < np; ++i) {
628: length = de->messages_to_be_sent[i] * de->unit_message_size;
629: dest = ((char*)de->send_message) + de->unit_message_size * de->message_offsets[i];
630: MPI_Isend( dest, length, MPI_CHAR, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]);
631: }
632: PetscLogEventEnd(DMSWARM_DataExchangerBegin,0,0,0,0);
633: return(0);
634: }
636: /* do the actual message passing now */
637: PetscErrorCode DMSwarmDataExEnd(DMSwarmDataEx de)
638: {
639: PetscMPIInt i,np;
640: PetscInt total;
641: PetscInt *message_recv_offsets;
642: void *dest;
643: PetscInt length;
647: if (de->communication_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Communication has not been initialized. Must call DMSwarmDataExInitialize() first.");
648: if (!de->recv_message) SETERRQ( de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first");
649: PetscLogEventBegin(DMSWARM_DataExchangerEnd,0,0,0,0);
650: np = de->n_neighbour_procs;
651: PetscMalloc1(np+1, &message_recv_offsets);
652: message_recv_offsets[0] = 0;
653: total = de->messages_to_be_recvieved[0];
654: for (i = 1; i < np; ++i) {
655: message_recv_offsets[i] = total;
656: total = total + de->messages_to_be_recvieved[i];
657: }
658: /* == NON BLOCKING == */
659: for (i = 0; i < np; ++i) {
660: length = de->messages_to_be_recvieved[i] * de->unit_message_size;
661: dest = ((char*)de->recv_message) + de->unit_message_size * message_recv_offsets[i];
662: MPI_Irecv( dest, length, MPI_CHAR, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np+i]);
663: }
664: MPI_Waitall( 2*np, de->_requests, de->_stats);
665: PetscFree(message_recv_offsets);
666: de->communication_status = DEOBJECT_FINALIZED;
667: PetscLogEventEnd(DMSWARM_DataExchangerEnd,0,0,0,0);
668: return(0);
669: }
671: PetscErrorCode DMSwarmDataExGetSendData(DMSwarmDataEx de,PetscInt *length,void **send)
672: {
674: if (de->packer_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being packed.");
675: *length = de->send_message_length;
676: *send = de->send_message;
677: return(0);
678: }
680: PetscErrorCode DMSwarmDataExGetRecvData(DMSwarmDataEx de,PetscInt *length,void **recv)
681: {
683: if (de->communication_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being sent.");
684: *length = de->recv_message_length;
685: *recv = de->recv_message;
686: return(0);
687: }
689: PetscErrorCode DMSwarmDataExTopologyGetNeighbours(DMSwarmDataEx de,PetscMPIInt *n,PetscMPIInt *neigh[])
690: {
692: if (n) {*n = de->n_neighbour_procs;}
693: if (neigh) {*neigh = de->neighbour_procs;}
694: return(0);
695: }