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