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 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 */ 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 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 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 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 */ 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 */ 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 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 === */ 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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